Skip to main content
.md

Tasks

Six tasks drawn as genome-browser tracks over one locus: promoter probability, a gene model, splice junctions, enhancer activity, chromatin features, and an expression window.

Six tasks, each its own published operationPOST /v1/tasks/promoter/predict, /v1/tasks/splice/predict, /v1/tasks/enhancer/predict, /v1/tasks/chromatin/predict, /v1/tasks/annotation/predict, /v1/tasks/expression/predict — plus two workflows that compose them. The URLs are exactly the strings you already POST to; what changed is that each now has its own request schema, its own minLength, and its own closed options object, instead of one shared PredictRequest. (Regenerate typed clients built against the old shared model.) The same six tasks are also tools over MCP.

Each accepts a DNA sequence (and a sequence_name label) and returns task-specific fields under data; meta is uniform across tasks. Request and response schemas — with copyable examples — are in ReDoc; per-task length caps and latency are in Limits.

TaskInput (bp)Model windowStrand-sensitiveOutput
Promoter300–500,0002,000 (300 on the *-300bp models)Yes (coding strand)Promoter-region probabilities
Splice100–500,00015,000Yes (transcript orientation)Donor / acceptor sites
Enhancer50–500,000249Yes (dev/hk channels)dev + hk activity scores
Chromatin200–500,0001,000No919 features in 8 track groups
Expression9,198–500,000 (+ tss_index)— (trained_window_bp 9,198)Yes (coding strand)Expression in log(TPM+1)
Annotation1,000–500,000Plus-strand inputTranscripts with type + exon/intron/CDS structure (GFF3)
Find genes + expression1,000–500,000Plus-strand inputGenes found, each with a predicted expression
Variant interpretationA VCF, not a sequenceCoordinates, not strandAn annotated copy of your VCF, written back to your bucket

Where a task is marked strand-sensitive, submit DNA 5'→3' on the gene's coding (sense) strand; for annotation, submit the plus-strand region.

GET /v1/tasks/{task}/models returns {task, default_model, models}; each model's is_default marks the default. The model-list endpoint is authoritative for what each task currently serves.

The "input" column is the accepted range, enforced before any model loads. The "model window" is the model's own context_window_bp: a sequence above the floor but below that window is still scored — against a window padded out to it. See the floor is admission control, not regime.

Model selection

Each task has a default_model and may offer alternatives. List them with GET /v1/tasks/{task}/models (a flat {task, default_model, models} object, not the {data, meta} envelope; it needs the same bearer key, and an unknown task is 404 not_found). To pick one, pass its id in the top-level model field of the request bodynot options.model: every task's options object is closed, so an unrecognised key there is 422 validation_failed with loc ["body","options","model"].

Each model's bio_spec carries request_max_bp (the enforced ceiling), context_window_bp (its own window) and trained_window_bp (a fixed receptive field where it has one) — see Limits. Beyond the default human models, promoter offers species-specific variants (Drosophila, yeast, Arabidopsis), and DNABERT k-mer variants exist for promoter, enhancer, and chromatin. The model-list endpoint is authoritative for what each task currently serves; the same roster and default are also published statically as x-models on each predict operation in /v1/openapi.json, for tooling that wants it without a live call.

Options

options is typed and closed per task: unknown keys are rejected with 422 validation_failed (type: extra_forbidden) rather than ignored. The complete set:

Taskoptions keysRequired
Promoterthreshold (0–1, default 0.5)
Splicethreshold (0–1, default 0.5), site_types (subset of ["donor","acceptor"], default both)
Enhancernone — the object accepts no fields
Chromatinthreshold (0–1, default 0.5)
Annotationbatch_size (1–128, default 8), shift_coordinates (string, e.g. "UCSC"), reverse_complement (bool, default true)
Expressiondescription (string)description, and options itself
Find genes + expressiondescription, annotation_model, expression_model, batch_size (1–128, default 8), shift_coordinatesoptions itself; description enforced at runtime

The tasks, one card each

Each task below has its own notes, an example call from the kit client and from an MCP host, then Applications and Usage tips. On the rendered page (docs.genomicintelligence.ai/tasks) each card also carries Input, Options and Output panels, generated at build time from the pinned /v1/openapi.json so they cannot drift from it; Source on a panel opens that operation in ReDoc. The prose does not restate those schemas; outside the panels, read them in ReDoc or in /v1/openapi.json itself.

POST /v1/tasks/promoter/predict

Promoter

Binary classification that detects promoter regions. The default g0-promoter-2000bp is a G0 BERT-Large encoder trained on human promoters from EPDnew. Inputs above 2,000 bp are scanned in windows automatically.

  • sequence: floor set by the smallest context_window_bp among the promoter models (bounds in the table above); below g0-promoter-2000bp's own 2,000 bp window the input is padded out to it.
  • options.threshold (0–1, default 0.5): probability cutoff for calling a window a promoter. The only key PromoterOptions accepts.
  • Strand-sensitive — submit the coding (sense) strand.

Output: per-window promoter probabilities. Also BED and bedGraph?format=json|bed|bedgraph (see output formats).

API reference

POST /v1/tasks/promoter/predict

Scan a sequence for promoter regions.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputPromoterPredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 300 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 300–500,000 bp. The 300 bp floor applies to every promoter model — it is the smallest context_window_bp among them, i.e. the shortest input that fills some promoter model's window exactly, with no padding. Requests outside the range are rejected with 422 validation_failed before any model is loaded. Note that minLength is admission control, not a statement about regime: a sequence at least this long but shorter than the selected model's context_window_bp (published by GET /v1/tasks/{task}/models) is accepted and scored, but against a window padded out to that size. Compare your length against that field to know whether the model saw real sequence or padding. Longer input is never a problem — the scanner steps one prediction window at a time and pads only the final partial window.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsPromoterOptionsSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • thresholdnumber0 – 1default 0.5
OutputPredictResponseSource ↗
  • dataPromoterDatarequired
    Show PromoterData fields (7)
    • modelstringrequired
      Model id that produced this result.
    • inputPromoterInputrequired
      The caller's label for the submitted sequence, echoed verbatim; nothing derived. The submitted length is meta.sequence_length.
      Show PromoterInput fields (1)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "promoter"
    • regionsobject[]required
      Detected promoter regions (start/end/score).
    • window_detailsobject[]required
      Per-window scoring detail (one entry per scanned window).
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsPromoterCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show PromoterCounts fields (3)
      • taskstringrequired= "promoter"
      • windows_processedintegerrequired
        Number of sliding windows scored.
      • regions_foundintegerrequired
        Detected promoter regions in this call.

Applications

Use it to locate transcription start regions in unannotated sequence, or to score designed constructs for promoter strength inside an optimisation loop. The per-window detail in data.window_details makes it usable as a fitness signal rather than only a binary call.

Usage tips

  • The floor is 300 bp — the minLength on this operation's request schema. It is a property of the endpoint, so choosing a different model does not lower it.
  • Input shorter than the model's window is padded, not rejected. A 300 bp submission is scored against g0-promoter-2000bp's 2,000 bp window; compare your length with bio_spec.context_window_bp from GET /v1/tasks/promoter/models before reading much into a marginal call.
  • Submit the coding (sense) strand. The task is strand-sensitive.
POST /v1/tasks/splice/predict

Splice

Token-level classification labeling each position as a splice acceptor (3' site), donor (5' site), or neither. The default g0-splice-bigbird is a G0 BigBird encoder trained on human splice sites from SpliceAI. Long inputs are scanned in a 15,000 bp sliding window; predictions are most reliable in the central region of each window.

  • sequence: the floor (bounds in the table above) is well below the model's 15,000 bp window, so short submissions are scored against heavy padding — treat 15,000 bp as the in-regime size.

  • options.threshold (0–1, default 0.5): score cutoff for emitting a site. A response carrying more than 20,000 sites is refused with 422 validation_failed — only a very low threshold on a long sequence gets there. If you want everything, use 1e-3, not 0: it is numerically equivalent (no score moved by more than 4.6e-4 in our benchmark), ~4x faster, and stays under the cap. See Limits.

  • options.site_types: subset of ["donor", "acceptor"] (default both). With threshold, the only two keys SpliceOptions accepts.

  • Strand-specific — submit the transcript's orientation. The wrong strand does not fail loudly, and it does not return near-zero scores either: it returns sites at different positions, often still at high confidence. On our BRCA1 fixture the reverse complement scored 0.9101 and 0.9946 where gene-sense scored 0.9998 and 0.9999; on SMN1 it returned 1 site instead of 17. Neither the site count nor the scores give you a usable check, and there is no strand flag in the contract, so track orientation on your side.

  • start/end bound the scored token, not the junction. The model reads your sequence as BPE tokens and scores whole tokens, so a site's span is that token's character range — typically 4–8 bp, and varying from site to site because token lengths do. A donor or acceptor junction is a single base. token_index names the token the span came from. Do not treat the span as the feature's extent, and be careful intersecting it with a base-resolution reference annotation: at that scale it will be quietly wrong. We publish no derived base position — deriving one from a token score would be a modelling claim we cannot currently defend, and invented precision in a file you keep is worse than an honest span. Stated in the contract since revision 5.

Output: detected acceptor and donor sites with scores. Also BED and GFF3?format=json|bed|gff3 (see output formats). The GFF3 source column carries the model id (g0-splice-bigbird); it read gpu_service before contract revision 4. Columns 4–5 of that GFF3 are the token spans described above, so a saved track has token resolution, not base resolution.

API reference

POST /v1/tasks/splice/predict

Annotate donor and acceptor splice sites.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputSplicePredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 100 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 100–500,000 bp. The 100 bp floor applies to every splice model — it is the splice model's own gate. Requests outside the range are rejected with 422 validation_failed before any model is loaded. Note that minLength is admission control, not a statement about regime: a sequence at least this long but shorter than the selected model's context_window_bp (published by GET /v1/tasks/{task}/models) is accepted and scored, but against a window padded out to that size. Compare your length against that field to know whether the model saw real sequence or padding. Longer input is never a problem — the scanner steps one prediction window at a time and pads only the final partial window.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsSpliceOptionsSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • site_typesstring[] | null
    Subset of ["donor", "acceptor"]; default both.
  • thresholdnumber0 – 1default 0.5
OutputPredictResponseSource ↗
  • dataSpliceDatarequired
    Show SpliceData fields (8)
    • modelstringrequired
      Model id that produced this result.
    • inputSpliceInputrequired
      The caller's label for the submitted sequence, echoed verbatim; nothing derived. The submitted length is meta.sequence_length.
      Show SpliceInput fields (1)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "splice"
    • sitesobject[]required
      Detected splice sites (donor / acceptor). start/end bound the scored BPE token, not the junction. The model reads the sequence as byte-pair-encoded tokens and scores whole tokens, so each site's span is that token's character range — typically 4–8 bp, and varying site to site because token lengths do — while a donor or acceptor junction is a single base. token_index names the token. Treating the span as the feature's extent, or intersecting it with a base-resolution reference annotation, will be quietly wrong at that scale. The same spans are what ?format=gff3 writes into columns 4–5, where they outlive the response that produced them. No base-resolution position is published: deriving one from a token score would be a modelling claim the service cannot currently defend, and an invented precision in a saved file is worse than an honest span (GH#58).
    • tracksobjectrequired
      Per-position score tracks for visualization.
    • window_detailsobject[]required
      Per-window scoring detail.
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsSpliceCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show SpliceCounts fields (3)
      • taskstringrequired= "splice"
      • windows_processedintegerrequired
      • sites_foundintegerrequired
        Detected splice sites (donor + acceptor).

Applications

Use it to locate exon boundaries in unannotated transcripts, to check whether a designed edit creates or destroys a splice site, or to screen variants for splice disruption by scoring the reference and the edited sequence side by side.

Usage tips

  • Submit the transcript's orientation. The wrong strand does not fail loudly: it returns sites at different positions, often at high confidence, and no score or count identifies a mis-oriented submission afterwards. Reverse-complement minus-strand genes before you call.
  • A site's start/end is a token span, not the junction base — typically 4–8 bp. Locate a boundary to within the span; do not reduce it to one base or intersect it with base-resolution annotation as though it were one.
  • The floor is 100 bp, the window 15,000 bp. Treat 15,000 bp as the in-regime size.
  • Do not send threshold: 0. A response over 20,000 sites is refused with 422 validation_failed; 1e-3 returns effectively everything and stays under the cap.
POST /v1/tasks/enhancer/predict

Enhancer

Regression predicting two scores per window: developmental (dev) and housekeeping (hk). The default g0-deepstarr is a G0 BERT-Base encoder trained on Drosophila enhancers from DeepSTARR. The sequence is split into consecutive, non-overlapping 249 bp windows, each scored independently.

  • sequence: the floor (bounds in the table above) is admission control — the shortest input g0-deepstarr will admit — not a useful size: the model scores 249 bp windows, so anything shorter is accepted and scored against a padded window. Submit ≥ 249 bp to stay in regime.
  • options: EnhancerOptions accepts no fields. Send {} or omit it; any key is a 422. There is no threshold on this task — it is regression, not classification.

The model is Drosophila-trained and strand-sensitive for the dev/hk channels — use a fly sequence on the gene's coding (sense) strand.

Output: per-window dev and hk scores, embedding bedGraph renderings of each track. bedGraph is also available directly — ?format=json|bedgraph (see output formats).

API reference

POST /v1/tasks/enhancer/predict

Score enhancer activity (developmental and housekeeping).

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputEnhancerPredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 50 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 50–500,000 bp. The 50 bp floor applies to every enhancer model — it is g0-deepstarr's gate; the k-mer model tolerates shorter input but is unaffected above the floor. Requests outside the range are rejected with 422 validation_failed before any model is loaded. Note that minLength is admission control, not a statement about regime: a sequence at least this long but shorter than the selected model's context_window_bp (published by GET /v1/tasks/{task}/models) is accepted and scored, but against a window padded out to that size. Compare your length against that field to know whether the model saw real sequence or padding. Longer input is never a problem — the scanner steps one prediction window at a time and pads only the final partial window.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsEnhancerOptionsSource ↗

EnhancerOptions accepts no fields: send {} or omit options.

OutputPredictResponseSource ↗
  • dataEnhancerDatarequired
    Show EnhancerData fields (7)
    • modelstringrequired
      Model id that produced this result.
    • inputEnhancerInputrequired
      The caller's label for the submitted sequence, echoed verbatim; nothing derived. The submitted length is meta.sequence_length.
      Show EnhancerInput fields (1)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "enhancer"
    • windowsobject[]required
      Per-window enhancer scores.
    • tracksobjectrequired
      Per-position score tracks for visualization.
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsEnhancerCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show EnhancerCounts fields (2)
      • taskstringrequired= "enhancer"
      • windows_processedintegerrequired

Applications

Use it to rank candidate enhancers, or as a dual-objective fitness function when designing regulatory elements that favour one programme (developmental or housekeeping) over the other.

Usage tips

  • The floor is 50 bp, the lowest of the six, but the model scores 249 bp windows. Submit at least 249 bp to stay in regime.
  • The developmental/housekeeping split is a Drosophila STARR-seq definition (DeepSTARR). Read the two scores as relative activity within a comparison, not as calibrated cross-species values.
  • Send no options. EnhancerOptions accepts no fields: send {} or omit it; any key is a 422.
POST /v1/tasks/chromatin/predict

Chromatin

Multi-label classification predicting 919 mammalian chromatin features (DeepSEA-style), grouped into eight categories (DNase, CTCF, Pol2, c-Myc, H3K27ac, H3K27me3, H3K4me1, Other). The default g0-deepsea is a G0 BERT-Base encoder trained on ENCODE data. The sequence is tiled into 1,000 bp windows stepping every 200 bp.

  • sequence: the model's window is 1,000 bp (floor in the table above), so submit at least that to avoid padding.
  • options.threshold (0–1, default 0.5): only features scoring above this are returned. The only key ChromatinOptions accepts.

Output: per-feature probabilities (above the threshold), grouped by category. Also BED?format=json|bed (see output formats).

API reference

POST /v1/tasks/chromatin/predict

Annotate chromatin features (DeepSEA-style, 919 labels).

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputChromatinPredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 200 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 200–500,000 bp. The 200 bp floor applies to every chromatin model — both chromatin models use it. Requests outside the range are rejected with 422 validation_failed before any model is loaded. Note that minLength is admission control, not a statement about regime: a sequence at least this long but shorter than the selected model's context_window_bp (published by GET /v1/tasks/{task}/models) is accepted and scored, but against a window padded out to that size. Compare your length against that field to know whether the model saw real sequence or padding. Longer input is never a problem — the scanner steps one prediction window at a time and pads only the final partial window.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsChromatinOptionsSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • thresholdnumber0 – 1default 0.5
OutputPredictResponseSource ↗
  • dataChromatinDatarequired
    Show ChromatinData fields (7)
    • modelstringrequired
      Model id that produced this result.
    • inputChromatinInputrequired
      The caller's label for the submitted sequence, echoed verbatim; nothing derived. The submitted length is meta.sequence_length.
      Show ChromatinInput fields (1)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "chromatin"
    • windowsobject[]required
      Per-window chromatin annotations.
    • tracksobjectrequired
      Per-position score tracks for visualization.
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsChromatinCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show ChromatinCounts fields (3)
      • taskstringrequired= "chromatin"
      • windows_processedintegerrequired
      • total_annotationsintegerrequired
        Sum of per-track annotation counts across all windows.

Applications

Use it to ask whether a sequence looks accessible, bound, or marked, and to compare designed variants against a natural reference across many assays at once.

Usage tips

  • The floor is 200 bp; the window is 1,000 bp. Submit at least 1,000 bp to avoid padding.
  • Lowering threshold grows the response. Only features scoring above it are returned, and each window is scored on all 919.
  • A count is not a cell type. meta.task_specific_counts.total_annotations sums calls across every window and every feature; a high count is not evidence about any one cellular context. Read the individual features for that.
POST /v1/tasks/expression/predict

Expression

Predicts gene expression from a DNA sequence plus an experimental-context description, on a log(TPM+1) scale. The default g0-expression is trained on ENCODE RNA-seq across cell types.

Expression has its own operation and request schema — POST /v1/tasks/expression/predict, ExpressionPredictRequest — as every task now does. It remains the only one that takes a tss_index and the only one whose options has a required field.

The body accepts exactly five fields — sequence (required), options (required), tss_index, sequence_name, model — and is closed: any other top-level key returns 422 validation_failed.

  • sequence (required): 9,198–500,000 bp, gene-sense strand. The model scores exactly one 9,198 bp window (4,599 bp each side of the TSS) — shorter input is a hard 422, never padded or truncated. Lengths are counted after whitespace is stripped, so a line-wrapped FASTA body pastes verbatim (the > header line does not).

  • tss_index (integer, 0-based): offset of the TSS into the whitespace-stripped sequence. Required unless sequence is exactly 9,198 bp, where it defaults to 4599. Must satisfy 4599 <= tss_index <= len(sequence) - 4599. The server scores sequence[tss_index - 4599 : tss_index + 4599]. It does not discover the TSS for you and does not reverse-complement. See Limits for the full rules and the silent-wrong-window gotcha.

  • options.description (required): free-text experimental context (cell type, assay, conditions). options is a closed object — description is its only accepted key, and it must be non-empty. Omitting it returns 422 validation_failed.

    This string is model input, not a label. It conditions the prediction, and the exact wording changes the number: on one fixture, same sequence and same model, "K562" scored 1.38 and "K562 cells" scored 0.70 log(TPM+1) — roughly a 2x spread in TPM from phrasing alone. There is no enum and no canonical vocabulary. Pick one form and keep it fixed: when you compare predictions across sequences, runs, or releases, a changed description invalidates the comparison as surely as a changed sequence.

Output: data.prediction = {expression, expression_log_tpm, expression_tpm, unit}expression/expression_log_tpm are log(TPM+1); expression_tpm is the back-transformed linear value. JSON only (no text-track formats; ?format= anything but json is 415 unsupported_format).

Windowing provenance is echoed back in two places: meta.task_specific_counts (and data.input) carry tss_index and scored_window — the half-open [start, end] of your submitted sequence that was actually scored, always exactly 9,198 bp wide. The length you submitted (whitespace-stripped) is meta.sequence_length, also echoed as data.input.submitted_sequence_length; the scored width is always 9,198 bp, which is scored_window[1] - scored_window[0]. (data.input.sequence_length was removed at contract revision 13.)

API reference

POST /v1/tasks/expression/predict

Predict gene expression from a TSS-centred window.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputExpressionPredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 9,198 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; all lengths and tss_index are measured against the whitespace-stripped string. Must be at least 9198 bp — one full TSS-centred training window — and is windowed server-side down to exactly that many bp around tss_index before inference.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
  • tss_indexinteger | null≥ 0
    0-based offset of the transcription start site into the whitespace-stripped sequence (i.e. count nucleotides, not file characters — a line-wrapped FASTA would otherwise be off by its newline count). The server scores sequence[tss_index-4599 : tss_index+4599] and echoes the applied window back in meta.task_specific_counts. Required unless sequence is exactly 9198 bp, in which case it defaults to 4599 (the only legal value). Must satisfy 4599 <= tss_index <= len(sequence) - 4599; out-of-range is a 422 rather than an N-padded guess.
OptionsExpressionOptionsrequiredSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • descriptionstringrequiredlength ≥ 1
    Experimental context (cell type, assay, conditions). Required — the model is conditioned on it, e.g. "assay term name is polyA plus RNA-seq. biosample summary is Homo sapiens K562."
OutputPredictResponseSource ↗
  • dataExpressionDatarequired
    Show ExpressionData fields (6)
    • modelstringrequired
      Model id that produced this result.
    • inputExpressionInputrequired
      Echo of the request: the caller's sequence_name, the description the prediction was conditioned on, and the tss_index the server applied. The window that offset produced is meta.task_specific_counts.scored_window; the submitted length is meta.sequence_length.
      Show ExpressionInput fields (3)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
      • descriptionstringrequired
        The experimental context the prediction was conditioned on (cell type / assay), echoed from options.description.
      • tss_indexintegerrequired
        The 0-based TSS offset the server applied, into the whitespace-stripped sequence that was submitted. Echoes the request's tss_index, or the 4599 implied by a submission of exactly 9198 bp. The window it produced is meta.task_specific_counts.scored_window.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "expression"
    • predictionobjectrequired
      Expression prediction record: {expression, expression_log_tpm, expression_tpm, unit}.
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsExpressionCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show ExpressionCounts fields (3)
      • taskstringrequired= "expression"
      • scored_windowinteger[] | null
        [start, end] — the half-open slice of the submitted, whitespace-stripped sequence that was fed to the model. Always exactly 9198 bp wide: [tss_index-4599, tss_index+4599].
      • tss_indexinteger | null
        0-based TSS offset the server applied, into the whitespace-stripped sequence that was submitted. Echoes the request's tss_index, or the implied 4599 when the submission was exactly 9198 bp.

Applications

Use it to estimate the transcriptional output of a locus or a designed promoter under a stated cellular context, and as the objective in an expression-maximising or expression-matching design loop.

Usage tips

  • The window is exact. Submit exactly 9,198 bp centred on the TSS, or a longer locus plus tss_index and let the service cut it. Under-length input is rejected, never padded.
  • description is conditioning text, not a label. It is fed to the model, so rewording it changes the prediction. Hold it fixed across runs you intend to compare.
  • An in-range but wrong tss_index still scores — a different window, with a confident 200. Read the applied window back from meta.task_specific_counts.scored_window rather than assuming the request's.
  • The sequence is never reverse-complemented. Submit minus-strand genes in transcript orientation.
POST /v1/tasks/annotation/predict

Annotation

Gene finding over long DNA: detects transcripts and returns their intervals. The g0-annotation model (multispecies) predicts transcript boundaries, transcript type (mRNA / lnc_RNA), and full internal exon/intron/CDS structure, and emits a browser-ready GFF3 track. Submit the plus-strand genomic region; the model finds transcripts on both strands. This is the longest-running task, and the only predict operation with a hard sync cap: above 200,000 bp a synchronous JSON request is refused with 413 sync_too_large, details = {sequence_length, threshold} — resend the identical body with Prefer: respond-async. Below that, sync works at any accepted length, but prefer async above ~30,000 bp (see Asynchronous jobs). The cap is on JSON delivery only: ?format=bed and ?format=gff3 are served synchronously at any accepted length, so size those calls against the 300 s proxy timeout yourself.

  • sequence: the highest floor of the five non-expression tasks (bounds in the table above); the gene finder cannot work below its own window.
  • model (optional, top-level): g0-annotation — the only annotation model, selected by default.
  • options.batch_size (integer 1–128, default 8): windows processed per batch.
  • options.shift_coordinates: "UCSC": rebase output coordinates from a UCSC-style sequence_name (e.g. chr8:127,680,000-127,800,000). Note that the header goes in sequence_name (≤ 128 chars), not in the sequence — a > line inside the sequence fails the alphabet check.
  • options.reverse_complement (bool, default true): average each locus with its reverse complement, improving minus-strand recall. Set false for a faster single-pass run.

AnnotationOptions accepts those three keys and nothing else.

Output: transcript intervals, each carrying its own strand (+/-) plus tss_position and polya_position. Each transcript additionally carries transcript_type, transcript_type_score, and 0-based half-open exons/introns/cds arrays, and data.formats.gff3 holds a full GFF3 track (also via Accept: text/x-gff3). BED is also available — ?format=json|bed|gff3. See output formats.

API reference

POST /v1/tasks/annotation/predict

Find genes and their exon/intron/CDS structure.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputAnnotationPredictRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 1,000 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 1,000–500,000 bp. The 1,000 bp floor applies to every annotation model — the gene finder needs that much context to be meaningful. This is the bound the document previously advertised as 1 bp. Requests outside the range are rejected with 422 validation_failed before any model is loaded.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsAnnotationOptionsSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • batch_sizeinteger1 – 128default 8
  • reverse_complementbooleandefault true
    Structure-aware models (g0-annotation) only: average each locus with its reverse complement (improves minus-strand recall). Set false for a faster, single-pass smoke run. Ignored by boundary-only models.
  • shift_coordinatesstring | null
    Set to "UCSC" to shift coordinates from a UCSC-style FASTA header (e.g. >chr8:1000-2000).
OutputPredictResponseSource ↗
  • dataAnnotationDatarequired
    Show AnnotationData fields (6)
    • modelstringrequired
      Model id that produced this result.
    • inputAnnotationInputrequired
      The caller's label for the submitted sequence, echoed verbatim; nothing derived. The submitted length is meta.sequence_length.
      Show AnnotationInput fields (1)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
    • summaryobjectrequired
      Task-specific summary statistics. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • taskstringrequired= "annotation"
    • transcriptsobject[]required
      Detected transcripts. Every transcript carries gene boundaries (start/end/strand/score) plus tss_position and polya_position. Structure-aware models (g0-annotation) additionally populate transcript_type (mRNA/lnc_RNA), transcript_type_score and 0-based half-open exons/introns/cds arrays. The formats object exposes bed and, for structure-aware models, a full gff3 track (also available via Accept: text/x-gff3).
    • formatsobject | null
      Optional per-format pre-rendered text payloads (BED/GFF3/…). In every GFF3 this service generates, column 2 (source) is the id of the model that produced the feature — the same value as model above — so a saved track records its own provenance. The one exception is a structure-aware model whose upstream pipeline emits its own canonical GFF3 (annotation's g0-annotation): that document is passed through verbatim and keeps its producer's source value, which names a multi-stage pipeline rather than one model.
  • metaMetarequired
    Metadata envelope shared by every successful predict response.
    Show Meta fields (9)
    • job_idstringrequired
      Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope. Quote it in support requests: it is the one handle that identifies a call whether it succeeded or failed.
    • taskstringrequired
      Task name (matches the {task} URL segment). Use this — or data.task — to narrow the typed unions.
    • modelstringrequired
      Model id that ran this inference.
    • cold_startbooleanrequired
      True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
    • model_load_time_msintegerrequired
      Milliseconds spent loading the model (0 when cold_start is False).
    • inference_time_msintegerrequired
      Milliseconds spent running inference.
    • sequence_lengthintegerrequired
      Length of the submitted sequence (bp).
    • task_specific_countsAnnotationCountsrequired
      Discriminated counts payload (see per-task *Counts models).
      Show AnnotationCounts fields (2)
      • taskstringrequired= "annotation"
      • transcripts_foundintegerrequired

Applications

Use it to annotate assembled contigs or synthetic constructs where no reference annotation exists, and to supply TSS positions (tss_position) to expression when they are not known in advance.

Usage tips

  • The floor is 1,000 bp, the highest of the five non-expression tasks.
  • One submission finds both strands. Submit the plus-strand region; each transcript carries its own strand, relative to the sequence as submitted.
  • This is the slowest task, and the only predict operation with a sync cap. Above 200,000 bp a synchronous JSON request is 413 sync_too_large; send Prefer: respond-async and poll. Below the cap async is a latency preference, not a requirement.
  • reverse_complement: false is a faster single pass, at some cost in minus-strand recall.
POST /v1/workflows/find-genes-and-predict-expression

Find genes and predict expression

POST /v1/workflows/find-genes-and-predict-expression — a composite that chains the two tasks server-side: annotate the region, centre a 9,198 bp window on each found gene's TSS, and score expression for each. One round trip, no intermediate results shuttled back to your client, and no tss_index to compute.

It is a published operation on the same bearer key as everything else; nothing needs enabling.

  • sequence: 1,000–500,000 bp — annotation's floor, since the workflow cannot find a gene in less sequence than the gene finder looks at.
  • options (required), and options.description (required — the expression stage is conditioned on it; missing or empty is 422 validation_failed, "options.description is required (cell type / assay context)"). Also accepts annotation_model, expression_model, batch_size (1–128, default 8), shift_coordinates. Closed, like every other options.
  • Above 50,000 bp synchronous delivery is refused with 413 sync_too_large, details = {sequence_length, threshold}. Resend the identical body with Prefer: respond-async and poll GET /v1/tasks/jobs/{job_id} (see Asynchronous jobs). This is the lower of the contract's two sync caps; annotation carries the other, at 200,000 bp.

Output: data.expression_predictions[], one entry per gene found; a gene the workflow could not score carries a skip_reason. meta.task_specific_counts = {genes_found, genes_predicted, genes_skipped}, with genes_predicted + genes_skipped == genes_found. Unlike the direct expression endpoint, the workflow pads a TSS window with N up to half its width rather than dropping a gene near the edge of your region. JSON only.

API reference

POST /v1/workflows/find-genes-and-predict-expression

Annotate a raw DNA sequence then predict per-gene expression.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputFindGenesAndPredictExpressionRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • sequencestringrequiredlength 1,000 – 500,000pattern ^\s*(?:[ACGNTacgnt]\s*)+$
    DNA sequence (A/C/G/T/N, case-insensitive). Whitespace (newlines, spaces, tabs) is stripped first, so a line-wrapped FASTA sequence body may be pasted verbatim; length is measured against the whitespace-stripped string, not the raw character count — so a line-wrapped body can satisfy the published minLength as a raw string and still be rejected once stripped. Count bases, not characters. 1,000–500,000 bp. The 1,000 bp floor applies to every annotation model — the annotation stage sets it — the workflow cannot find a gene in less sequence than the gene finder looks at. Requests outside the range are rejected with 422 validation_failed before any model is loaded.
  • modelstring | nulllength ≤ 128
    Model ID. If omitted, the task's default model is used. The valid ids and the default for this operation are published structurally as x-models on the operation itself — deliberately not as an enum here, so that adding a model cannot make a previously-generated client reject a valid id. GET /v1/tasks/{task}/models carries the same roster with full per-model specs.
  • sequence_namestring | nulllength ≤ 128default "sequence"
    Display name for the sequence (e.g., 'chr1:1000-5000').
OptionsFindGenesAndPredictExpressionOptionsrequiredSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • descriptionstringrequiredlength ≥ 1
    Experimental context (cell type, assay, conditions) applied to every found gene. Required — the expression stage is conditioned on it.
  • annotation_modelstring | nulllength ≤ 128
  • batch_sizeinteger1 – 128default 8
  • expression_modelstring | nulllength ≤ 128
  • shift_coordinatesstring | null
OutputFindGenesAndPredictExpressionResponseSource ↗
  • dataFindGenesAndPredictExpressionDatarequired
    data shape for POST /v1/workflows/find-genes-and-predict-expression.
    Show FindGenesAndPredictExpressionData fields (7)
    • taskstringrequired= "find_genes_and_predict_expression"
    • annotation_modelstringrequired
    • expression_modelstringrequired
    • inputFindGenesAndPredictExpressionInputrequired
      Echo of the request: sequence_name and the description the expression stage was conditioned on. The submitted length is not echoed here — read meta.sequence_length.
      Show FindGenesAndPredictExpressionInput fields (2)
      • sequence_namestringrequired
        The caller's label for the submitted sequence, echoed verbatim. Defaults to "sequence" when the request omitted it.
      • descriptionstringrequired
        The experimental context the expression stage was conditioned on, echoed from options.description.
    • summaryobjectrequired
      Aggregate stats: gene counts plus avg/min/max expression across non-skipped predictions. Its keys are deliberately not part of this contract: they are per-task statistics that may be added, renamed or removed without a contract revision, so consumers must not depend on them — branch on the typed fields (meta and this payload's own declared keys) instead.
    • annotationobjectrequired
      Annotation stage's full data payload (same shape as AnnotationData).
    • expression_predictionsGeneExpressionPredictionData[]required
      One record per gene found by annotation.
      Show GeneExpressionPredictionData fields (9)
      • gene_indexintegerrequired
      • gene_namestringrequired
      • strandstringrequiredone of "+", "-"
      • tss_positionintegerrequired
        TSS coordinate within the input sequence (bp).
      • centered_sequence_lengthintegerrequired
      • expressionnumberrequired
        log(TPM + 1).
      • expression_tpmnumberrequired
      • skippedbooleanrequired
      • skip_reasonstring | null
        Present when skipped=True; missing otherwise.
  • metaFindGenesAndPredictExpressionMetarequired
    meta shape for POST /v1/workflows/find-genes-and-predict-expression. Inherits the spine fields from the simple-task Meta (job_id, cold_start, *_time_ms, sequence_length, task_specific_counts) but adds the composite-specific keys: per-stage model ids and per-stage timing blocks. model is the canonical concatenation "<annotation_model>+<expression_model>" — the same string the Web UI displays as the run identifier.
    Show FindGenesAndPredictExpressionMeta fields (13)
    • job_idstringrequired
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header and identical to error.request_id on the failure envelope.
    • taskstringrequired= "find_genes_and_predict_expression"
      Workflow name. Present so meta.task is required on every success envelope, composite included, and always agrees with data.task.
    • modelstringrequired
      Composite identifier: "<annotation_model>+<expression_model>". Use annotation_model / expression_model for the parts.
    • cold_startbooleanrequired
      True if EITHER stage had to load its model for this request.
    • model_load_time_msintegerrequired
      Sum of per-stage load times (annotation + expression).
    • inference_time_msintegerrequired
      Sum of per-stage inference times.
    • sequence_lengthintegerrequired
    • task_specific_countsFindGenesAndPredictExpressionCountsrequired
      meta.task_specific_counts shape for the composite workflow. Invariant: genes_predicted + genes_skipped == genes_found.
      Show FindGenesAndPredictExpressionCounts fields (3)
      • genes_foundintegerrequired
        Genes detected by the annotation stage on the input sequence.
      • genes_predictedintegerrequired
        Genes whose expression was successfully predicted (TSS-centered window resolved + expression model returned a value).
      • genes_skippedintegerrequired
        Genes annotation found but the expression stage skipped — usually because the TSS-centered window would extend past the input sequence. data.expression_predictions[].skip_reason carries the per-gene cause.
    • annotation_modelstringrequired
    • expression_modelstringrequired
    • annotationStageTimingsrequired
      Annotation stage cold-start + timing.
      Show StageTimings fields (3)
      • cold_startbooleanrequired
        True if the stage's model had to be loaded for this request.
      • model_load_time_msintegerrequired
        Milliseconds spent loading.
      • inference_time_msintegerrequired
        Milliseconds spent running inference.
    • expressionStageTimingsrequired
      Expression stage cold-start + timing.
      Show StageTimings fields (3)
      • cold_startbooleanrequired
        True if the stage's model had to be loaded for this request.
      • model_load_time_msintegerrequired
        Milliseconds spent loading.
      • inference_time_msintegerrequired
        Milliseconds spent running inference.

Applications

Use it when the TSS positions are not known in advance: it annotates and scores a whole locus in one call, rather than you chaining annotation into expression yourself.

Usage tips

  • The floor is 1,000 bp (annotation's), and the ceiling is this endpoint's own 500,000 bp, which is not the expression model's window.
  • Above 50,000 bp, go async. A synchronous request is 413 sync_too_large; resend the identical body with Prefer: respond-async. This is the lower of the contract's two sync caps.
  • A gene near the edge of your region is still scored: its window is padded with N rather than the gene dropped. A gene the workflow could not score carries skip_reason, and genes_predicted + genes_skipped == genes_found.
  • JSON only. Unlike the predict operations it has no ?format= parameter.
POST /v1/workflows/genomic-variant-interpretation

Genomic variant interpretation

POST /v1/workflows/genomic-variant-interpretation — the one operation that does not take a DNA sequence. You give it the s3:// URI of a VCF in your own object storage; it scores the variants that fall near a transcription start site and writes an annotated copy beside it, named after it. The JSON you get is a receipt: where the annotated file is, and how the run went. You never parse a VCF to drive the workflow, and the annotation format inside it can change without breaking anything you built.

Under development

This workflow is not finished. The contract below is real and will not change silently, but the per-tissue values in an annotated file are not final and are not yet to be read as results. A run is model output when, and only when, the response carries meta.model and the annotated VCF carries a ##GEXModel header line — until both appear, treat the numbers as format rather than findings. It also needs a grant on your bucket before it will run for you, so talk to us rather than integrating against it unannounced.

Asynchronous only. A whole-exome case runs for hours, well past any proxy timeout, so Prefer: respond-async is required; a request without it is 400 bad_request. There is no callback — submit, then poll GET /v1/tasks/jobs/{job_id} (see Asynchronous jobs).

POST /v1/workflows/genomic-variant-interpretation
Authorization: Bearer gi_...
Prefer: respond-async
Content-Type: application/json
{
"input": { "type": "s3_object", "uri": "s3://your-bucket/cases/CASE-00123/sample.vcf.gz" },
"client_ref": "CASE-00123",
"options": { "genome_build": "GRCh37" }
}

You name the VCF itself, not a folder — nothing else in the prefix is listed or read, so a manifest, an index, or a second VCF beside it are all irrelevant, and the format of your own case metadata stays yours. Everything the analysis needs arrives as typed options. The key must end in .vcf, .vcf.gz or .vcf.bgz; uncompressed, bgzip- and plain gzip-compressed files are all accepted and you never need to recompress anything.

The annotated copy is written beside the input, named after it and after the job: sample.vcf.gz becomes sample.annotated.<job>.vcf.gz in the same prefix, where <job> is the first eight characters of the job_id. Read the exact name from data.output.uri rather than constructing it.

The job is in the name because the input alone does not identify a run: analysing one VCF against two different panels produces two different results, and under an input-only name the second would overwrite the first while the first receipt — retained for 24 hours — still pointed at it. Two VCFs in one folder are likewise two independent cases. A resubmission resolves to the same job and so rewrites the same object rather than accumulating copies.

Grant the service s3:GetObject on the object and s3:PutObject on its prefix. No s3:ListBucket is needed, because nothing searches.

  • input.type: s3_object today. The field is a discriminated union so another kind of input — an inline VCF, a presigned URL — can be added without breaking this one.
  • options.genome_build (required): GRCh37. A VCF header declares its assembly only sometimes, and guessing misplaces every window.
  • options.window: bp from a start site within which a variant is scored. Default 5000, range 1–100,000.
  • options.tissues: cell-type contexts, one scoring run each. Default ["heart", "liver", "brain"], 1–16 entries. The expression model is conditioned on these strings and the exact wording moves the result.
  • options.genes: restrict scoring to a panel. Accepts HGNC symbols (BRCA1) or Ensembl gene ids with or without a version (ENSG00000141510, ENSG00000141510.17); symbols are case-insensitive, up to 1,000 entries. Omit it to score every gene near a variant.
  • client_ref: an opaque string of yours, ≤128 characters, echoed back. It carries your case identity so this API never has to model a case.

The request is validated before the job is accepted. All of these are 400 bad_request on the POST, so a typo costs a second rather than a poll cycle through a job that fails minutes later: a URI that is not s3://bucket/key; one naming a prefix rather than an object; a key not ending .vcf, .vcf.gz or .vcf.bgz; an object this service cannot read (check the s3:GetObject grant); an empty VCF, or one over 2 GiB; a genes identifier matching no gene; a genome_build with no published start-site catalogue. Anything that goes wrong after acceptance is a job failure visible on the poll — including a file that turns out to be unreadable, or to already carry GEX_* fields, neither of which can be known until it is opened.

A panel is the difference between a long case and a short one. Unrestricted, a whole exome scores tens of thousands of allele-to-start-site pairs; restricted to a handful of genes it scores a handful. Records near a start site that is not in your panel are still written to the output, flagged NO_REQUESTED_GENE_IN_WINDOW — deliberately distinct from OUTSIDE_TSS_WINDOW, because "you did not ask about this gene" and "there was no start site here" are different answers, and a narrow panel should not read as a coverage gap. The resolved panel is echoed in meta.options_applied.genes and recorded in the output VCF's ##GEXRequestedGenes header, so a restricted run cannot later be mistaken for a whole-genome one. An identifier matching no MANE Select gene is a 400 naming every unresolved one — a panel silently missing a gene would return a result that looks complete and is not.

Submitting the same case twice gives you the same job. The job_id is derived from your key, input.uri, the input object's ETag, client_ref and options, so a retry after an ambiguous failure — or a restarted integration — resolves to the run you already have rather than starting a second hours-long pass over the same object. There is no idempotency header to send. Two consequences worth knowing: a failed job re-runs on resubmission, and to deliberately re-run a case that succeeded, change client_ref. Replacing the VCF under an unchanged path also yields a new job, since its ETag is part of the derivation.

Accepted submissions return 202 with data = {job_id, status: "accepted", links}, plus X-Job-Id and Content-Location. On completion the poll returns:

{
"data": {
"task": "genomic_variant_interpretation",
"client_ref": "CASE-00123",
"status": "ok",
"output": { "type": "s3_object", "uri": "s3://your-bucket/cases/CASE-00123/sample.annotated.3eaecf69.vcf.gz" },
"counts": {
"variants_in": 73771,
"annotated": 12721,
"not_run": 61050,
"not_run_reasons": { "OUTSIDE_TSS_WINDOW": 61050 },
"annotated_alleles": 12725,
"associations": 14698,
"skipped_alleles": 10
}
},
"meta": {
"task": "genomic_variant_interpretation",
"genome_build": "GRCh37",
"job_id": "…", "request_id": "…",
"input": { "type": "s3_object", "uri": "s3://your-bucket/cases/CASE-00123/sample.vcf.gz" },
"gene_annotation": {
"build": "v50lift37",
"md5": "bed31c2cead98e9e1989ef7943fb3206",
"transcripts": "MANE Select",
"start_sites": 19153
},
"options_applied": { "window": 5000, "tissues": ["heart", "liver", "brain"], "genes": null }
}
}

Every input record reaches the output, scored or not, so annotated + not_run == variants_in and you can diff input against output record for record. A record that could not be scored is flagged in place with GEX_NOT_RUN and a reason in GEX_NOT_RUN_REASONOUTSIDE_TSS_WINDOW, NO_TSS_ON_CONTIG, NO_SUPPORTED_ALT, or NO_REQUESTED_GENE_IN_WINDOW when you sent a panel — rather than dropped. The same four appear in counts.not_run_reasons, which sums to not_run. A record with some usable and some unusable ALT alleles — a symbolic allele beside a plain one, say — lists the unusable ones in GEX_SKIPPED_ALT and is still annotated for the rest, so a record can carry both keys. Scored records carry GEX_ANN, one VEP-style entry per supported ALT allele and nearby transcript: Allele|Gene|Gene_ID|Transcript_ID|TSS|Strand|TSS_distance| then one log2 fold-change field per requested tissue. Distances are strand-aware, negative upstream, and the output header records the convention along with the window and the GENCODE release the start sites came from — and the model, once one is named. meta.input echoes the object you named, so a stored receipt names both what was read and what was written. counts.associations is the unit of scoring work — allele-to-start-site pairs, not records — so it is the number to reason about when sizing a case, and meta.gene_annotation is the machine-readable form of that provenance.

meta.model tells you whether these are model output. While this workflow is under development the field is absent, as is the annotated VCF's ##GEXModel header line — the run is not attributed to a model that did not produce the values. Both appear, naming the model, once it is. Everything around them is real today: your file is read, every record is matched against GENCODE v50lift37 MANE Select start sites, every record is written back, and the counts are computed from it.

Submitting a VCF that already carries GEX_* fields — an annotated copy from a previous run, for instance — is a 400: submit the original. Results are retained for 24 hours and then return 410. The annotated file in your own bucket is not on that clock. A job does not survive a deployment of this service: in-flight work is lost and the poll reports 503 with a message to resubmit, so retries belong to you.

This workflow is REST-only — it is not exposed as an MCP tool.

API reference

POST /v1/workflows/genomic-variant-interpretation

Score the variants in a VCF and return an annotated copy.

Open this operation in ReDoc ↗, with the request and response schemas, every status code, and copyable examples.

InputGenomicVariantInterpretationRequestSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • inputS3ObjectInputrequired
    Show S3ObjectInput fields (2)
    • typestringrequired= "s3_object"
    • uristringrequiredlength 8 – 1,024pattern ^s3://[^/]+/.+
      Full s3://bucket/key URI of the VCF to read, e.g. s3://bucket/cases/CASE-00123/sample.vcf.gz. The key must end in .vcf, .vcf.gz or .vcf.bgz; nothing else in the prefix is listed, opened or read. The annotated copy is written beside it, named after it and after the jobsample.vcf.gz yields sample.annotated.<job>.vcf.gz in the same prefix, where <job> is the first eight characters of the job_id. Read the exact name from data.output.uri rather than constructing it. Two VCFs in one prefix therefore produce two distinct outputs, and so do two different analyses of the SAME VCF — running one file against several panels is the ordinary case, and without the job in the name the second run would overwrite the first while the first receipt still pointed at it. This service must be granted s3:GetObject on the object and s3:PutObject on its prefix; s3:ListBucket is not required.
  • client_refstring | nulllength ≤ 128
    Opaque caller string, never parsed, echoed back in the result. It carries the caller's own case identity so this API does not have to model a case. It does participate in this submission's identity: the job id is derived from the request, so changing client_ref is how you deliberately re-run a case that already succeeded. Hashing is not parsing.
OptionsGenomicVariantInterpretationOptionsrequiredSource ↗

Closed (additionalProperties: false): a key not listed here is rejected, not ignored.

  • genome_buildstringrequired= "GRCh37"
    Assembly the VCF's coordinates refer to. Required — a VCF header declares it only sometimes, and guessing it silently misplaces every window. GRCh37 is the only build with a published start-site catalogue; the enum will gain a value when another is published, which is additive.
  • genesstring[] | null1 – 1,000 items
    Restrict scoring to these genes — a panel. Omit the field entirely to score every gene near a variant; an empty list is a 422, because a panel of nothing scores nothing and would otherwise return a green receipt with zero annotations that looks like a coverage result. Accepts HGNC symbols (BRCA1) or Ensembl gene ids with or without a version (ENSG00000141510, ENSG00000141510.17); symbols are case-insensitive. An identifier that matches no MANE Select gene is a 400 naming every unresolved one, rather than being dropped — a panel silently missing a gene returns a result that looks complete and is not. Omit it to score every gene near a variant. Supplying one is the difference between tens of thousands of scored windows and a handful, so a case restricted to a panel finishes in a fraction of the time. Records near a start site that is not in the panel are written through with GEX_NOT_RUN_REASON=NO_REQUESTED_GENE_IN_WINDOW, which is distinct from OUTSIDE_TSS_WINDOW: the first says you did not ask, the second says there was nothing there.
  • tissuesstring[]1 – 16 itemsdefault ["heart","liver","brain"]
    Cell-type contexts to score, one model run each. The expression model is conditioned on these strings and the exact wording moves the prediction. Defaults to ['heart', 'liver', 'brain'].
  • windowinteger1 – 100,000default 5000
    Maximum distance in bp from a transcription start site for a variant to be scored.
OutputGenomicVariantInterpretationResponseSource ↗
  • dataGenomicVariantInterpretationDatarequired
    data for POST /v1/workflows/genomic-variant-interpretation. A receipt, not a payload. The predictions live in the annotated VCF at output.uri; this envelope says where that object is and how the run went, so a caller can orchestrate the workflow without parsing a VCF.
    Show GenomicVariantInterpretationData fields (5)
    • taskstringrequired= "genomic_variant_interpretation"
    • statusstringrequired= "ok"
      Present so the payload reads as a receipt. A failed run is a failed job: it comes back as the natural 4xx/5xx with the error envelope, never as a 200 saying failed.
    • outputVariantObjectRefrequired
      The annotated copy, written beside the input and named after it and the job: sample.vcf.gz becomes sample.annotated.<job>.vcf.gz in the same prefix. Read the name from here rather than constructing it.
      Show VariantObjectRef fields (2)
      • typestringrequired= "s3_object"
      • uristringrequired
        Fully qualified s3:// object URI. For an output, the name is derived from the input's and the job's — read it from here rather than constructing it.
    • countsGenomicVariantInterpretationCountsrequired
      data.counts for the variant workflow. Invariant: annotated + not_run == variants_in. Every input record is written to the output, whether or not it could be scored.
      Show GenomicVariantInterpretationCounts fields (7)
      • variants_inintegerrequired
        Records read from the input VCF.
      • annotatedintegerrequired
        Records carrying a prediction in the output.
      • not_runintegerrequired
        Records written through unscored — typically because no transcription start site falls within options.window, or because it belongs to a gene outside options.genes. See not_run_reasons for the breakdown.
      • annotated_allelesintegerdefault 0
        ALT alleles carrying a prediction. Exceeds annotated where a record is multiallelic.
      • associationsintegerdefault 0
        Allele-to-start-site pairs scored — the unit of model work, not the record count. One allele near three start sites is three.
      • not_run_reasonsmap<string, integer>
        Why records were not scored, by reason: OUTSIDE_TSS_WINDOW, NO_TSS_ON_CONTIG, NO_SUPPORTED_ALT, NO_REQUESTED_GENE_IN_WINDOW. Sums to not_run. A reason with no records is omitted.
      • skipped_allelesintegerdefault 0
        ALT alleles ineligible for scoring (symbolic, breakends, the spanning deletion *), listed per record in GEX_SKIPPED_ALT. A record can be annotated for its other alleles and still have some counted here.
    • client_refstring | null
      Echo of the request's client_ref, verbatim.
  • metaGenomicVariantInterpretationMetarequired
    meta for the variant workflow. Carries the provenance a result needs to stay interpretable months later: which assembly, which models, and the options actually applied — which may differ from those requested only by defaulting.
    Show GenomicVariantInterpretationMeta fields (8)
    • job_idstringrequired
    • request_idstringrequired
      Correlation id for this request, mirrored on the X-Request-Id response header.
    • taskstringrequired= "genomic_variant_interpretation"
    • genome_buildstringrequired
    • gene_annotationGeneAnnotationProvenancerequired
      Which start-site catalogue produced this result. Published in the receipt as well as the annotated VCF's header because the receipt is what a caller stores, and these values move when the science does.
      Show GeneAnnotationProvenance fields (4)
      • buildstringrequired
        GENCODE release, e.g. v50lift37.
      • md5stringrequired
        MD5 of the GENCODE annotation the catalogue was built from.
      • start_sitesintegerrequired
        Start sites in the catalogue.
      • transcriptsstringdefault "MANE Select"
        Which transcripts carry a start site. One per gene today, so a gene with an alternative promoter is scored at its MANE start only — stated rather than implied by the release.
    • options_appliedGenomicVariantInterpretationOptionsAppliedrequired
      Window and tissues as the run actually used them.
      Show GenomicVariantInterpretationOptionsApplied fields (3)
      • windowintegerrequired
        TSS proximity window in bp.
      • tissuesstring[]required
        Cell-type contexts scored, in order.
      • genesstring[] | null
        The panel as resolved to Ensembl gene ids, or null when the run was not restricted. Resolved rather than echoed, so a caller can see what their symbols became.
    • inputVariantObjectRefrequired
      The VCF that was read — the object named by input.uri on the request. Echoed so a stored receipt is self-contained: it names both what was read and what was written. Always present.
      Show VariantObjectRef fields (2)
      • typestringrequired= "s3_object"
      • uristringrequired
        Fully qualified s3:// object URI. For an output, the name is derived from the input's and the job's — read it from here rather than constructing it.
    • modelstring | null
      The model that produced these values, and the marker that they are model output at all. Absent while this workflow is under development, as is the annotated VCF's ##GEXModel header line: the field is omitted rather than naming a model that did not produce the values. Read the per-tissue log2 fold changes as results only when both are present.

Applications

Use it to score the variants in a case's VCF that fall near a transcription start site, across the tissues you name, and get the annotated VCF back in your own bucket beside the input, where the rest of your pipeline already reads.

Usage tips

  • Async only. Prefer: respond-async is required; without it the request is 400 bad_request.
  • Send a gene panel when you have one. Restricted to a handful of genes a case scores a handful of allele-to-start-site pairs instead of tens of thousands.
  • The same case twice is the same job. To deliberately re-run a case that succeeded, change client_ref.
  • tissues are conditioning text. The exact wording moves the prediction, as with expression's description.
  • Not results yet. Until the response carries meta.model and the VCF a ##GEXModel header, treat the values as format rather than findings.

Next: Limits for caps and latency, or the REST API guide for the call walkthrough.