---
title: "Retrieve job progress or final result"
method: GET
path: "/v1/tasks/jobs/{job_id}"
tags: ["Tasks"]
---

# Retrieve job progress or final result

`GET /v1/tasks/jobs/{job_id}`

## Request

- Base URL: `https://api.genomicintelligence.ai`
- URL: `https://api.genomicintelligence.ai/v1/tasks/jobs/{job_id}`
- Auth: HTTP bearer

Unified progress + result endpoint.

HTTP status reflects the underlying job state. Owner-scoped:

- Unknown / not-owned → ``404 not_found``.
- Expired → ``410 job_expired``.
- Running / accepted → ``202`` with the canonical ``{data, meta}``
  envelope; ``data`` carries ``status`` and ``progress``.
- Completed → ``200`` with the same ``{data, meta}`` envelope sync
  mode would have produced.
- Failed → the natural ``4xx``/``5xx`` for the underlying error with
  the unified ``{error: {...}}`` envelope.

## Path parameters

- `job_id` string, required

## Response `200`

Job complete. Body is the same ``{data, meta}`` envelope the originating operation returns synchronously — one of three: a predict envelope for the six task endpoints (``data.task`` is ``promoter``, ``splice``, ``enhancer``, ``chromatin``, ``annotation`` or ``expression``), the composite envelope (``find_genes_and_predict_expression``), or the variant-workflow receipt (``genomic_variant_interpretation``). **Narrow on ``data.task``** — the literal is unique across all three and is the only discriminator. It is nested one level down, so this is an ``anyOf`` without an OpenAPI ``discriminator``, which names only top-level properties; a generated client must switch on ``data.task`` by hand rather than relying on first-match deserialization.

- union
  - PredictResponse: Success envelope for ``POST /v1/tasks/{task}/predict``.
    - `data` union, required
      - PromoterData: ``data`` shape for ``POST /v1/tasks/promoter/predict``.
        - `model` string, required: Model id that produced this result.
        - `input` PromoterInput, required: ``data.input`` for ``POST /v1/tasks/promoter/predict``.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'promoter', required
        - `regions` object[], required: Detected promoter regions (start/end/score).
        - `window_details` object[], required: Per-window scoring detail (one entry per scanned window).
      - SpliceData: ``data`` shape for ``POST /v1/tasks/splice/predict``.
        - `model` string, required: Model id that produced this result.
        - `input` SpliceInput, required: ``data.input`` for ``POST /v1/tasks/splice/predict``.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'splice', required
        - `sites` object[], 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).
        - `tracks` object, required: Per-position score tracks for visualization.
        - `window_details` object[], required: Per-window scoring detail.
      - EnhancerData: ``data`` shape for ``POST /v1/tasks/enhancer/predict``.
        - `model` string, required: Model id that produced this result.
        - `input` EnhancerInput, required: ``data.input`` for ``POST /v1/tasks/enhancer/predict``.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'enhancer', required
        - `windows` object[], required: Per-window enhancer scores.
        - `tracks` object, required: Per-position score tracks for visualization.
      - ChromatinData: ``data`` shape for ``POST /v1/tasks/chromatin/predict``.
        - `model` string, required: Model id that produced this result.
        - `input` ChromatinInput, required: ``data.input`` for ``POST /v1/tasks/chromatin/predict``.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'chromatin', required
        - `windows` object[], required: Per-window chromatin annotations.
        - `tracks` object, required: Per-position score tracks for visualization.
      - AnnotationData: ``data`` shape for ``POST /v1/tasks/annotation/predict``.
        - `model` string, required: Model id that produced this result.
        - `input` AnnotationInput, required: ``data.input`` for ``POST /v1/tasks/annotation/predict``.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'annotation', required
        - `transcripts` object[], 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``).
      - ExpressionData: ``data`` shape for ``POST /v1/tasks/expression/predict``. ``input`` echoes the request only: ``sequence_name``, ``description`` and the ``tss_index`` the server applied. The windowing provenance the server derived from that offset is in ``meta`` — which part of the submission the model used is ``meta.task_specific_counts.scored_window`` (see that field), and the submitted length is ``meta.sequence_length``.
        - `model` string, required: Model id that produced this result.
        - `input` ExpressionInput, required: ``data.input`` for ``POST /v1/tasks/expression/predict``. Three echoes, all of them things the caller sent or the server chose on the caller's behalf. ``tss_index`` is the second kind: it is optional on the request and defaults to 4599 when the submission is exactly 9,198 bp, so the echo is the only statement of which offset was actually applied. What is **not** here, deliberately: ``scored_window`` (read ``meta.task_specific_counts.scored_window``) and ``submitted_sequence_length`` (read ``meta.sequence_length``). Both were derived twins of a ``meta`` field.
          - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
          - `description` string, required: The experimental context the prediction was conditioned on (cell type / assay), echoed from ``options.description``.
          - `tss_index` integer, required: 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``.
        - `summary` object, required: 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.
        - `formats` object, nullable: 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.
        - `task` 'expression', required
        - `prediction` object, required: Expression prediction record: ``{expression, expression_log_tpm, expression_tpm, unit}``.
    - `meta` Meta, required: Metadata envelope shared by every successful predict response.
      - `job_id` string, required: Server-generated UUIDv4. Mirrored on the X-Job-Id response header.
      - `request_id` string, required: 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.
      - `task` string, required: Task name (matches the {task} URL segment). Use this — or ``data.task`` — to narrow the typed unions.
      - `model` string, required: Model id that ran this inference.
      - `cold_start` boolean, required: True if the model had to be loaded into GPU memory for this request. Useful for diagnosing first-request latency.
      - `model_load_time_ms` integer, required: Milliseconds spent loading the model (0 when cold_start is False).
      - `inference_time_ms` integer, required: Milliseconds spent running inference.
      - `sequence_length` integer, required: Length of the submitted sequence (bp).
      - `task_specific_counts` union, required: Discriminated counts payload (see per-task ``*Counts`` models).
        - PromoterCounts
          - `task` 'promoter', required
          - `windows_processed` integer, required: Number of sliding windows scored.
          - `regions_found` integer, required: Detected promoter regions in this call.
        - SpliceCounts
          - `task` 'splice', required
          - `windows_processed` integer, required
          - `sites_found` integer, required: Detected splice sites (donor + acceptor).
        - EnhancerCounts
          - `task` 'enhancer', required
          - `windows_processed` integer, required
        - ChromatinCounts
          - `task` 'chromatin', required
          - `windows_processed` integer, required
          - `total_annotations` integer, required: Sum of per-track annotation counts across all windows.
        - AnnotationCounts
          - `task` 'annotation', required
          - `transcripts_found` integer, required
        - ExpressionCounts: Expression has no per-call counts — the prediction is a single value. What it carries instead is *windowing provenance*: an expression model reads a stretch of sequence around the TSS (how much depends on the model and on the sequence), while a caller may submit up to 500,000 bp. These fields report which part of the submission the model used (see ``scored_window``), so the contract is verifiable from the response alone rather than taken on trust. Always populated by ``POST /v1/tasks/expression/predict``.
          - `task` 'expression', required
          - `tss_index` integer, nullable: 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.
          - `scored_window` integer[], nullable: ``[start, end]`` — the half-open slice of the submitted, whitespace-stripped sequence the server cut for the model. For ``g0-expression`` it is the 9198 bp slice ``[tss_index-4599, tss_index+4599]``, of which the model reads the central part (roughly 3 kb on each side of the TSS, depending on sequence). For a model whose ``bio_spec.trained_window_bp`` is null it is the span actually read, so its width shows how much flank was used.
  - FindGenesAndPredictExpressionResponse: Success envelope for ``POST /v1/workflows/find-genes-and-predict-expression``. Published in the partner OpenAPI document. Also returned by ``GET /v1/tasks/jobs/{job_id}`` when the polled job is a composite run, so that operation's ``200`` is a union of this and :class:`PredictResponse`.
    - `data` FindGenesAndPredictExpressionData, required: ``data`` shape for ``POST /v1/workflows/find-genes-and-predict-expression``.
      - `task` 'find_genes_and_predict_expression', required
      - `annotation_model` string, required
      - `expression_model` string, required
      - `input` FindGenesAndPredictExpressionInput, required: ``data.input`` for the composite workflow. No ``tss_index``: the composite windows each gene itself and reports the result per gene in ``data.expression_predictions[].tss_position``.
        - `sequence_name` string, required: The caller's label for the submitted sequence, echoed verbatim. Defaults to ``"sequence"`` when the request omitted it.
        - `description` string, required: The experimental context the expression stage was conditioned on, echoed from ``options.description``.
      - `summary` object, required: 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.
      - `annotation` object, required: Annotation stage's full ``data`` payload (same shape as ``AnnotationData``).
      - `expression_predictions` GeneExpressionPredictionData[], required: One record per gene found by annotation.
        - `gene_index` integer, required
        - `gene_name` string, required
        - `strand` '+' | '-', required
        - `tss_position` integer, required: TSS coordinate within the input sequence (bp).
        - `centered_sequence_length` integer, required
        - `expression` number, required: log(TPM + 1).
        - `expression_tpm` number, required
        - `skipped` boolean, required
        - `skip_reason` string, nullable: Present when skipped=True; missing otherwise.
    - `meta` FindGenesAndPredictExpressionMeta, required: ``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.
      - `job_id` string, required
      - `request_id` string, required: Correlation id for this request, mirrored on the X-Request-Id response header and identical to ``error.request_id`` on the failure envelope.
      - `task` 'find_genes_and_predict_expression', required: Workflow name. Present so ``meta.task`` is required on every success envelope, composite included, and always agrees with ``data.task``.
      - `model` string, required: Composite identifier: "<annotation_model>+<expression_model>". Use ``annotation_model`` / ``expression_model`` for the parts.
      - `cold_start` boolean, required: True if EITHER stage had to load its model for this request.
      - `model_load_time_ms` integer, required: Sum of per-stage load times (annotation + expression).
      - `inference_time_ms` integer, required: Sum of per-stage inference times.
      - `sequence_length` integer, required
      - `task_specific_counts` FindGenesAndPredictExpressionCounts, required: ``meta.task_specific_counts`` shape for the composite workflow. Invariant: ``genes_predicted + genes_skipped == genes_found``.
        - `genes_found` integer, required: Genes detected by the annotation stage on the input sequence.
        - `genes_predicted` integer, required: Genes whose expression was successfully predicted (TSS-centered window resolved + expression model returned a value).
        - `genes_skipped` integer, required: 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_model` string, required
      - `expression_model` string, required
      - `annotation` StageTimings, required: Per-stage timing sub-block on the composite ``meta``.
        - `cold_start` boolean, required: True if the stage's model had to be loaded for this request.
        - `model_load_time_ms` integer, required: Milliseconds spent loading.
        - `inference_time_ms` integer, required: Milliseconds spent running inference.
      - `expression` StageTimings, required: Per-stage timing sub-block on the composite ``meta``.
        - `cold_start` boolean, required: True if the stage's model had to be loaded for this request.
        - `model_load_time_ms` integer, required: Milliseconds spent loading.
        - `inference_time_ms` integer, required: Milliseconds spent running inference.
  - GenomicVariantInterpretationResponse: Success envelope for ``POST /v1/workflows/genomic-variant-interpretation``.
    - `data` GenomicVariantInterpretationData, required: ``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.
      - `task` 'genomic_variant_interpretation', required
      - `client_ref` string, nullable: Echo of the request's ``client_ref``, verbatim.
      - `status` 'ok', required: 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``.
      - `output` VariantObjectRef, required: One S3 object: the case's input VCF, or the annotated copy of it.
        - `type` 's3_object', required
        - `uri` string, required: 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.
      - `counts` GenomicVariantInterpretationCounts, required: ``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.
        - `variants_in` integer, required: Records read from the input VCF.
        - `annotated` integer, required: Records carrying a prediction in the output.
        - `not_run` integer, required: 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.
        - `not_run_reasons` object: 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.
        - `annotated_alleles` integer: ALT alleles carrying a prediction. Exceeds ``annotated`` where a record is multiallelic.
        - `associations` integer: Allele-to-start-site pairs scored — **the unit of model work**, not the record count. One allele near three start sites is three.
        - `skipped_alleles` integer: 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.
    - `meta` GenomicVariantInterpretationMeta, required: ``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.
      - `job_id` string, required
      - `request_id` string, required: Correlation id for this request, mirrored on the X-Request-Id response header.
      - `task` 'genomic_variant_interpretation', required
      - `model` string, nullable: 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.
      - `genome_build` string, required
      - `gene_annotation` GeneAnnotationProvenance, required: The gene annotation the run was scored against.
        - `build` string, required: GENCODE release, e.g. ``v50lift37``.
        - `md5` string, required: MD5 of the GENCODE annotation the catalogue was built from.
        - `transcripts` string: 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.
        - `start_sites` integer, required: Start sites in the catalogue.
      - `options_applied` GenomicVariantInterpretationOptionsApplied, required: What the run actually used — which differs from the request only by defaulting, and is the only way a caller can confirm which tissues were scored.
        - `window` integer, required: TSS proximity window in bp.
        - `tissues` string[], required: Cell-type contexts scored, in order.
        - `genes` string[], nullable: 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.
      - `input` VariantObjectRef, required: One S3 object: the case's input VCF, or the annotated copy of it.
        - `type` 's3_object', required
        - `uri` string, required: 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.

## Other responses

- `202`: Job still running. Same ``{data, meta}`` envelope; ``data.progress.current_percent`` and ``data.progress.message`` carry live progress. Keep polling until 200.
- `400`: Bad request — e.g. `Prefer: respond-async` combined with a text format.
- `401`: Missing or invalid bearer key (`unauthorized`).
- `403`: Key disabled or insufficient tier (`forbidden`).
- `404`: Unknown task, unknown job, or a job owned by another key (`not_found`).
- `409`: Conflict (`conflict`).
- `410`: Async job result expired out of the job store (`job_expired`).
- `413`: Either the 16 MiB request-body hard cap was exceeded (`payload_too_large`, enforced before parsing), or the body is over the endpoint's synchronous-delivery cap (`sync_too_large`; `error.details` carries `{sequence_length, threshold}` — retry the same request with `Prefer: respond-async`).
- `415`: The requested output format is not one this task can render (`unsupported_format`). The message lists the supported formats; the server never silently falls back to JSON.
- `422`: Validation failed (`validation_failed`) — sequence length outside the task's bounds, a non-ACGTN character, an unknown key under `options` (every options object is closed), or a sequence below the *selected task's published `minLength`/`maxLength` bounds.
- `429`: Rate or concurrency cap reached (`too_many_requests`). `Retry-After` and the `RateLimit-*` headers say when to retry.
- `500`: Server error (`internal_error`).
- `503`: Model still loading (`model_loading`), GPU memory exhausted (`insufficient_memory`), or service unavailable. `insufficient_memory` means the card OOM-ed on this request and its cache has been released — it is transient GPU pressure, not a server bug, so `Retry-After` is honest and a bounded retry is the right response.

---

[API](https://skmtc.dev/genomicintelligence/apis/genomic-intelligence-api.md) · [All operations](https://skmtc.dev/genomicintelligence/apis/genomic-intelligence-api/llms.txt) · [OpenAPI document](https://skmtc.dev/genomicintelligence/apis/genomic-intelligence-api/revisions/72436b86d4fe?raw)
