{"openapi":"3.1.0","info":{"title":"open-deeplife-api (public API)","version":"1.0.0","description":"Public data-plane API for SDK and automation. Authenticate with the `X-API-Key` header."},"paths":{"/v1/predictions":{"post":{"tags":["data-plane: predictions"],"summary":"Create Prediction","description":"Create an async prediction request.\n\n**Multipart (choose one shape):**\n\n- **Merged single file:** ``dataset`` — one ``.h5ad`` (legacy TwinCell upload).\n- **Split inference:** ``dataset_control``, ``dataset_pert`` (two ``.h5ad`` files)\n  and ``degs`` — JSON array of HGNC-style gene symbols (same field names as the\n  ``deeplife-toolkit`` HTTP client). Optional: ``model_version``, ``label``.\n\n**job_type** (form field): ``target_id`` runs TwinCell inference (internal keys or\nmerged/split per policy). ``target_validation`` sends the same prediction queue with\n``job_type=target_validation`` so the model worker can route validation; requires\nform field ``target`` and split multipart inputs. External API keys may only use\n``target_validation``.\n\n**Worker parameters** (form fields, aligned with MLOps SQS):\n\n- ``target_id``: ``deg_significance_fold``, ``min_mean_expression``,\n  ``n_randomizations``\n- ``target_validation``: ``target``, ``deg_significance_fold``,\n  ``top_n_causal_degs``, ``min_path_fraction``, ``min_path_probability``,\n  optional ``max_path_length``, ``min_degs_fold_uniform``, ``prefix``\n\nSplit inputs are stored on S3 as ``dataset_control.h5ad``, ``dataset_pert.h5ad``,\nand ``degs.json`` under the prediction prefix; the queue message includes\n``dataset_s3_path`` (control object) and metadata with sibling paths for workers.\n\n**Execution order (fail-fast design):**\n1. Check inflight predictions (concurrency limit)\n2. Check quota (per-user limits)\n3. Check rate limit (spam/DDoS protection)\n4. Validate dataset (readable ``h5ad``; merged summaries are best-effort from\n   ``obs``. Split uploads run the same ``validate_twincell_split_anndata`` checks\n   as the public toolkit client.)\n5. Upload dataset to S3\n6. Enqueue to SQS for async processing\n\n**Important:** Dataset validation happens AFTER quota/inflight/rate-limit checks\nbut BEFORE any backend processing (S3 upload, SQS enqueue). This ensures users\ncannot trigger backend processing with invalid data, while still failing fast\non quota/rate limit violations.\n\nReturns 202 Accepted with prediction_id for async processing.","operationId":"create_prediction_v1_predictions_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_prediction_v1_predictions_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["data-plane: predictions"],"summary":"List Predictions","description":"List prediction requests for the authenticated user (paginated).","operationId":"list_predictions_v1_predictions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictionsListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/predictions/{prediction_id}/mapped-degs":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Mapped Degs","description":"Return DEGs that mapped onto the interactome for this prediction.","operationId":"get_prediction_mapped_degs_v1_predictions__prediction_id__mapped_degs_get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MappedDegsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/predictions/{prediction_id}/degs-impacted":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Degs Impacted","description":"Return DEGs whose influence on the prediction target exceeds the threshold.","operationId":"get_prediction_degs_impacted_v1_predictions__prediction_id__degs_impacted_get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DegsImpactedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/predictions/{prediction_id}/causal-paths":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Causal Paths","description":"Return redacted causal path rows for impacted DEGs (server-filtered).","operationId":"get_prediction_causal_paths_v1_predictions__prediction_id__causal_paths_get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CausalPathsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/predictions/{prediction_id}/intermediary-proteins":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Intermediary Proteins","description":"Return unique path node gene symbols (TwinCell ``df_paths`` flatten).","operationId":"get_prediction_intermediary_proteins_v1_predictions__prediction_id__intermediary_proteins_get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"top_n_degs","in":"query","required":true,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Restrict to paths whose ``deg`` is among the top-N DEGs ranked by ``score_deg_given_target`` (same rule as ``GET .../causal-graph``).","title":"Top N Degs"},"description":"Restrict to paths whose ``deg`` is among the top-N DEGs ranked by ``score_deg_given_target`` (same rule as ``GET .../causal-graph``)."},{"name":"deg","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Optional DEG filter (e.g. ``NDRG4|RNA``). When omitted, aggregates gene symbols from every node on each scanned path (capped row scan).","title":"Deg"},"description":"Optional DEG filter (e.g. ``NDRG4|RNA``). When omitted, aggregates gene symbols from every node on each scanned path (capped row scan)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntermediaryProteinsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/predictions/{prediction_id}/causal-graph":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Causal Graph Png","description":"Return a causal graph PNG **re-rendered on demand** from prediction artifacts.\n\n**When to use:** after a completed ``target_validation`` prediction (typical\nexternal / SDK flow). No separate causal-analysis job is required — the graph\nis derived from Parquet/JSON the worker uploaded with the prediction\n(``causal_graph_edges.parquet``, ``causal_paths.parquet``,\n``causal_graph_node_colors.json``).\n\n**Query params:** ``top_n_degs`` (required) restricts paths to the top-N DEGs\nby ``score_deg_given_target`` at render time (TwinCell\n``plot_causal_graph(..., top_n_causal_degs=...)``). Optional ``dpi`` controls\nPNG resolution (default 200).\n\n**Not the same as** ``GET /v1/causal-analysis/{causal_analysis_id}/graph``:\nthat route returns a pre-rendered PNG from a standalone async\n``causal_analysis`` job on a ``target_id`` prediction (internal workflow;\ncreate via ``POST /v1/causal-analysis``). Graph filters are fixed at job\nsubmission, not adjustable on GET.\n\nReturns 404 if the prediction is missing, not completed, or not allowed for\nthe caller's account tier. Returns 422 when required replay artifacts are\nabsent from storage.","operationId":"get_prediction_causal_graph_png_v1_predictions__prediction_id__causal_graph_get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"top_n_degs","in":"query","required":true,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Server-side Parquet replay: restrict to paths whose ``deg`` is among the top-N DEGs ranked by ``score_deg_given_target`` (TwinCell ``plot_causal_graph(..., top_n_causal_degs=...)``).","title":"Top N Degs"},"description":"Server-side Parquet replay: restrict to paths whose ``deg`` is among the top-N DEGs ranked by ``score_deg_given_target`` (TwinCell ``plot_causal_graph(..., top_n_causal_degs=...)``)."},{"name":"dpi","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":600,"minimum":72},{"type":"null"}],"description":"PNG render resolution (dots per inch). Default 200 when omitted (TwinCell ``plot_causal_graph``).","title":"Dpi"},"description":"PNG render resolution (dots per inch). Default 200 when omitted (TwinCell ``plot_causal_graph``)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Causal graph PNG rendered from Parquet/JSON artifacts in S3.","content":{"image/png":{}}},"404":{"description":"Prediction not found or graph not available."},"422":{"description":"Replay inputs missing or invalid (e.g. required Parquet/JSON absent)."},"500":{"description":"Internal error (e.g. storage unavailable). The response body is a generic message; see server logs for details."}}}},"/v1/predictions/{prediction_id}":{"get":{"tags":["data-plane: predictions"],"summary":"Get Prediction Status","description":"Get the status and results of a prediction request (API-key authenticated).","operationId":"get_prediction_status_v1_predictions__prediction_id__get","parameters":[{"name":"prediction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Prediction Id"}},{"name":"max_rows","in":"query","required":false,"schema":{"type":"integer","maximum":15000,"minimum":1,"description":"Max rows in `results` (target-score Parquet preview).","default":15000,"title":"Max Rows"},"description":"Max rows in `results` (target-score Parquet preview)."},{"name":"max_source_influence_rows","in":"query","required":false,"schema":{"type":"integer","maximum":50000,"minimum":1,"description":"Max rows in `source_influence_matrix` (paired `*_source_influence_score.parquet` preview).","default":50000,"title":"Max Source Influence Rows"},"description":"Max rows in `source_influence_matrix` (paired `*_source_influence_score.parquet` preview)."},{"name":"max_columns","in":"query","required":false,"schema":{"type":"integer","maximum":512,"minimum":1,"description":"Max columns to include in `source_influence_matrix` (paired `*_source_influence_score.parquet` preview).","default":512,"title":"Max Columns"},"description":"Max columns to include in `source_influence_matrix` (paired `*_source_influence_score.parquet` preview)."},{"name":"target","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":128},{"type":"null"}],"description":"Target entity id (e.g. ``BRAF|PROTEIN``) for external ``target_validation`` score lookup.","title":"Target"},"description":"Target entity id (e.g. ``BRAF|PROTEIN``) for external ``target_validation`` score lookup."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictionStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/causal-analysis":{"get":{"tags":["data-plane: causal-analysis"],"summary":"List causal analyses for a prediction","description":"List causal analyses (id, target, status) for one prediction (data plane).\n\nReturns an empty list if the prediction has no causal analyses.\nReturns 404 if the prediction does not exist or does not belong to the\nauthenticated user.","operationId":"list_causal_analyses_for_prediction_data_plane_v1_causal_analysis_get","parameters":[{"name":"prediction_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"Prediction ID to list causal analyses for.","title":"Prediction Id"},"description":"Prediction ID to list causal analyses for."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CausalAnalysisListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["data-plane: causal-analysis"],"summary":"Create Causal Analysis","description":"Create an async causal analysis job for a completed prediction.\n\nAccepts JSON body with prediction_id and target (single target per request).\nThe prediction must exist, belong to the authenticated user, and have\nstatus completed. Target must be an identifier present in the prediction's\ninference results.\n\nReturns 202 Accepted with causal_analysis_id for async processing.\nWorker posts status updates to the callback URL (see proposal doc).","operationId":"create_causal_analysis_v1_causal_analysis_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCausalAnalysisRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCausalAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/causal-analysis/{causal_analysis_id}/graph":{"get":{"tags":["data-plane: causal-analysis"],"summary":"Get Causal Analysis Graph","description":"Return the causal graph PNG for a completed **standalone causal-analysis job**.\n\n**When to use:** after ``POST /v1/causal-analysis`` on a completed\n``target_id`` prediction. Poll ``GET /v1/causal-analysis/{id}`` until\n``status`` is ``completed``, then fetch this route (or use inline\n``results.image_base64`` from the status response).\n\n**How it is produced:** the TwinCell worker renders the PNG once when the\nasync job finishes and stores it at ``result_s3_path``. This route downloads\nthat fixed image — graph options (``top_n_causal_degs``, path filters, etc.)\nwere set in the ``POST`` body, not as query params here.\n\n**Not the same as** ``GET /v1/predictions/{prediction_id}/causal-graph``:\nthat route re-renders on demand from prediction Parquet artifacts for\n``target_validation`` runs and requires ``top_n_degs``. External SDK users\nshould use the prediction artifact route, not this one.\n\nReturns 404 if the job is missing, not owned by the caller, not completed,\nor has no stored result file.","operationId":"get_causal_analysis_graph_v1_causal_analysis__causal_analysis_id__graph_get","parameters":[{"name":"causal_analysis_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Causal Analysis Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Causal graph PNG image (when job completed).","content":{"image/png":{}}},"404":{"description":"Causal analysis not found or not yet completed."},"500":{"description":"Internal error (e.g. storage unavailable). The response body is a generic message; see server logs for details."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/causal-analysis/{causal_analysis_id}":{"get":{"tags":["data-plane: causal-analysis"],"summary":"Get Causal Analysis Status","description":"Get status of a causal analysis job (API-key authenticated).\n\nWhen status is completed, results include the causal graph image (base64),\nsame pattern as prediction status with inline results.","operationId":"get_causal_analysis_status_v1_causal_analysis__causal_analysis_id__get","parameters":[{"name":"causal_analysis_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Causal Analysis Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CausalAnalysisStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_create_prediction_v1_predictions_post":{"properties":{"dataset":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Dataset"},"dataset_control":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Dataset Control"},"dataset_pert":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"Dataset Pert"},"degs":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degs"},"job_type":{"type":"string","title":"Job Type","default":"target_id"},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target"},"deg_significance_fold":{"type":"number","title":"Deg Significance Fold","default":1.0},"min_mean_expression":{"type":"number","title":"Min Mean Expression","default":0.1},"n_randomizations":{"type":"integer","title":"N Randomizations","default":0},"top_n_causal_degs":{"type":"integer","title":"Top N Causal Degs","default":1000},"min_path_fraction":{"type":"number","title":"Min Path Fraction","default":0.1},"min_path_probability":{"type":"number","title":"Min Path Probability","default":0.0001},"max_path_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Path Length"},"min_degs_fold_uniform":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Degs Fold Uniform"},"prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefix"},"model_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Version"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","title":"Body_create_prediction_v1_predictions_post"},"CausalAnalysisListItem":{"properties":{"causal_analysis_id":{"type":"string","format":"uuid","title":"Causal Analysis Id","description":"Unique ID of the causal analysis job."},"target":{"type":"string","title":"Target","description":"Target identifier that was requested for this analysis."},"status":{"type":"string","title":"Status","description":"Job status: pending, processing, completed, failed."}},"type":"object","required":["causal_analysis_id","target","status"],"title":"CausalAnalysisListItem","description":"One causal analysis in a list (id + target for differentiation)."},"CausalAnalysisListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CausalAnalysisListItem"},"type":"array","title":"Items","description":"Causal analyses for the prediction (id, target, status). Empty if none."}},"type":"object","title":"CausalAnalysisListResponse","description":"Response for listing causal analyses attached to one prediction.\n\nUsed by both data-plane (API key) and control-plane (JWT) list endpoints.\nEach item includes id and target so clients can differentiate analyses."},"CausalAnalysisResult":{"properties":{"image_base64":{"type":"string","title":"Image Base64","description":"Causal graph PNG as base64-encoded string (data URL or img src)."}},"type":"object","required":["image_base64"],"title":"CausalAnalysisResult","description":"Causal graph result (only when status is completed)."},"CausalAnalysisStatusResponse":{"properties":{"causal_analysis_id":{"type":"string","format":"uuid","title":"Causal Analysis Id"},"status":{"type":"string","title":"Status","description":"pending, processing, completed, failed"},"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"target":{"type":"string","title":"Target"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"results":{"anyOf":[{"$ref":"#/components/schemas/CausalAnalysisResult"},{"type":"null"}],"description":"Causal graph image (base64) when status is completed."},"artifacts":{"anyOf":[{"items":{"$ref":"#/components/schemas/PredictionArtifactItem"},"type":"array"},{"type":"null"}],"title":"Artifacts","description":"Presigned download URLs for worker outputs (from callback ``result_files``), when available."}},"type":"object","required":["causal_analysis_id","status","prediction_id","target","created_at"],"title":"CausalAnalysisStatusResponse","description":"Response for GET /v1/causal-analysis/{causal_analysis_id}.\n\nSame shape as prediction status: results are inline when completed.\nS3 paths are never exposed to clients; optional ``artifacts`` provides\npresigned URLs for all objects reported in the worker callback\n(``metadata.result_files``), e.g. graphs and sidecar Parquet."},"CausalPathRow":{"properties":{"deg":{"type":"string","title":"Deg"},"target":{"type":"string","title":"Target"},"path":{"type":"string","title":"Path","description":"Gene symbols along the path (no ``|RNA``/``|PROTEIN`` entity ids)."},"length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Length"},"score_path_given_target":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score Path Given Target","description":"Path score for ranking (TwinCell ``score_path_given_target``)."},"path_logFC":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Path Logfc","description":"Path log-fold change (TwinCell ``path_fraction``)."},"deg_logFC":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Deg Logfc","description":"DEG log-fold change (TwinCell ``score_deg_given_target``)."}},"type":"object","required":["deg","target","path"],"title":"CausalPathRow","description":"One causal path row for a single DEG query."},"CausalPathsResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"degs":{"items":{"type":"string"},"type":"array","title":"Degs","description":"Impacted DEG gene symbols used to filter paths (ordered, from worker artifact)."},"degs_total":{"type":"integer","minimum":0.0,"title":"Degs Total","description":"Total impacted DEG count from the worker artifact.","default":0},"paths":{"items":{"$ref":"#/components/schemas/CausalPathRow"},"type":"array","title":"Paths","description":"Redacted path rows for ``degs`` (all matching parquet rows, row cap applied)."}},"type":"object","required":["prediction_id"],"title":"CausalPathsResponse","description":"Response from GET ``/v1/predictions/{id}/causal-paths``."},"CreateCausalAnalysisRequest":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id","description":"ID of the completed prediction whose inference results to use."},"target":{"type":"string","minLength":1,"title":"Target","description":"Single target identifier to analyze (e.g. 'CTCF|PROTEIN'). Must exist in the prediction's inference results. One target per request."},"top_n_causal_degs":{"type":"integer","maximum":100000.0,"minimum":1.0,"title":"Top N Causal Degs","description":"Top-N impacting DEGs for path analysis (TwinCell :meth:`~twincell_v1.twincell.TwinCell.causal_analysis` default).","default":1000},"min_path_fraction":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Path Fraction","description":"Minimum fraction of a DEG's path mass to keep (TwinCell default).","default":0.1},"min_path_probability":{"type":"number","maximum":1.0,"exclusiveMinimum":0.0,"title":"Min Path Probability","description":"Discard paths below this raw probability (TwinCell default).","default":0.0001},"max_path_length":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Path Length","description":"Maximum path length in nodes; omit for TwinCell default (``model.n_propagation_steps``)."},"min_degs_fold_uniform":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Degs Fold Uniform","description":"Optional log-score fold threshold for DEG source selection. Omit for TwinCell default (top-``top_n_causal_degs`` selection only)."},"prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefix","description":"If the prediction produced multiple result sets (different parquet prefixes), use this to select one. Omit or null when there is only one."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Arbitrary key-value metadata; merged into worker ``metadata``."}},"type":"object","required":["prediction_id","target"],"title":"CreateCausalAnalysisRequest","description":"Request body for creating a causal analysis job.\n\nThe prediction must exist, belong to the authenticated user, and have\nstatus completed. Targets must be identifiers present in the prediction\ninference results (e.g. entity ids in the result Parquet).\n\nThe enqueued SQS body uses ``job_type=causal_analysis`` with ``top_n_causal_degs``,\n``min_path_probability``, optional ``max_path_length`` and\n``min_degs_fold_uniform``. Legacy ``n_top_path`` / ``degs_impact_fold_uniform``\nare not sent."},"CreateCausalAnalysisResponse":{"properties":{"causal_analysis_id":{"type":"string","format":"uuid","title":"Causal Analysis Id","description":"Unique ID for this causal analysis job."},"status":{"type":"string","title":"Status","description":"Current status: pending (queued), processing, completed, failed.","default":"pending"},"estimated_completion":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Completion","description":"Optional estimated completion time."}},"type":"object","required":["causal_analysis_id"],"title":"CreateCausalAnalysisResponse","description":"Response body for POST /v1/causal-analysis (202 Accepted)."},"DatasetSummaryResponse":{"properties":{"cell_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Type","description":"Single cell type (merged-upload summaries only; often null)."},"disease_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disease Label","description":"Disease/treatment label (merged-upload summaries only; often null)."},"n_cells":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Cells","description":"Number of cells (merged-upload summaries only; often null)."},"n_genes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Genes","description":"Number of genes (merged-upload summaries only; often null)."},"n_perturbations":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Perturbations","description":"Number of perturbations (merged-upload summaries only; often null)."},"n_degs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Degs","description":"Number of significant DEG symbols supplied (split uploads only)."}},"type":"object","title":"DatasetSummaryResponse","description":"Dataset context for display and filtering.\n\n**Legacy** single-file (merged) uploads may include a best-effort ``obs``-derived\nsummary (dimensions plus optional labels when inferrable). **Split** uploads\n(control + pert ``.h5ad`` + DEG list) do not infer labels from ``obs``; only counts\ntied to the user payload may appear\n(e.g. ``n_degs``)."},"DegsImpactedResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Target node id from the worker artifact (e.g. ``BRAF|PROTEIN``)."},"min_deg_fold_uniform":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Deg Fold Uniform","description":"Influence-score threshold used when the artifact was produced."},"degs":{"items":{"type":"string"},"type":"array","title":"Degs","description":"HGNC gene symbols whose source-influence score on ``target`` exceeded ``min_deg_fold_uniform``."}},"type":"object","required":["prediction_id"],"title":"DegsImpactedResponse","description":"Response from GET ``/v1/predictions/{id}/degs-impacted``."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IntermediaryProteinsResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"top_n_degs":{"type":"integer","title":"Top N Degs","description":"Top-N DEGs by ``score_deg_given_target`` used to filter paths before aggregation (same rule as ``GET .../causal-graph``)."},"deg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deg","description":"When set, proteins are taken from the best path for this DEG only."},"proteins":{"items":{"type":"string"},"type":"array","title":"Proteins","description":"Unique HGNC gene symbols from every node on each scanned path (``GENE|ENTITY`` → ``GENE``, TwinCell tutorial ``df_paths`` flatten)."},"n_paths_used":{"type":"integer","title":"N Paths Used","description":"Number of causal paths that contributed at least one node.","default":0}},"type":"object","required":["prediction_id","top_n_degs"],"title":"IntermediaryProteinsResponse","description":"Response from GET ``/v1/predictions/{id}/intermediary-proteins``."},"MappedDegsResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"degs":{"items":{"type":"string"},"type":"array","title":"Degs","description":"HGNC gene symbols for DEGs that mapped onto the interactome."}},"type":"object","required":["prediction_id"],"title":"MappedDegsResponse","description":"Response from GET ``/v1/predictions/{id}/mapped-degs``."},"PredictResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"status":{"type":"string","title":"Status","description":"Current status: pending, processing, completed, failed"},"estimated_completion":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Completion","description":"Estimated completion time (optional)."}},"type":"object","required":["prediction_id","status"],"title":"PredictResponse","description":"Prediction response body (async)."},"PredictionArtifactItem":{"properties":{"name":{"type":"string","title":"Name","description":"Stable basename for this artifact (from callback metadata ``result_files``)."},"url":{"type":"string","title":"Url","description":"Time-limited HTTPS URL to download the artifact."}},"type":"object","required":["name","url"],"title":"PredictionArtifactItem","description":"One downloadable output file produced by the worker (Option A)."},"PredictionResultRow":{"properties":{"id":{"type":"string","title":"Id","description":"Entity identifier (e.g. 'STAT2|PROTEIN')."},"score":{"type":"number","title":"Score","description":"Model score for this entity."},"rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank","description":"Rank (0 = best). May be null for some model outputs."},"rank_percentage":{"anyOf":[{"type":"number"},{"type":"integer"},{"type":"null"}],"title":"Rank Percentage","description":"Rank percentile (0..1). May be an int when equal to 0. May be null for some model outputs."},"pvalue":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pvalue","description":"P-value for this entity (internal/full results only)."},"z_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Z Score","description":"Z-score for this entity (internal/full results only)."},"protein_expressed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Protein Expressed","description":"Whether protein is expressed (internal/full results only)."},"is_deg":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Deg","description":"Whether this entity is considered differentially expressed. May be null for older predictions."},"node_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Node Type","description":"Node type in the model (internal/full results only)."},"n_degs_significant":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N Degs Significant","description":"Number of significant DEGs (internal/full results only)."},"percentage_degs_significant":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Percentage Degs Significant","description":"Percentage of significant DEGs (internal/full results only)."}},"type":"object","required":["id","score"],"title":"PredictionResultRow","description":"A single user-facing prediction result row.\n\nThis is derived from the Parquet file referenced by `result_s3_path` in the DB.\nThe API does not expose any S3 paths.\n\nPublic responses include a subset of columns; internal users (*@deeplife.co)\nreceive all target score columns."},"PredictionStatusResponse":{"properties":{"prediction_id":{"type":"string","format":"uuid","title":"Prediction Id"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"Stable failure code from the worker callback (for example ``target_not_reachable``). Present on failed target-validation runs when the worker reported structured metadata."},"error_detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Detail","description":"Technical failure detail (traceback / worker exception) for debugging. Returned only for internal (*@deeplife.co) accounts; external clients should use ``error_message``."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Optional user-provided or auto-generated display label for the run."},"job_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Type","description":"Job type from prediction creation (``target_id``, ``target_validation``). Used by clients and tier policy."},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Target protein entity id (e.g. ``BRAF|PROTEIN``) from target validation or causal analysis on this prediction."},"dataset_summary":{"anyOf":[{"$ref":"#/components/schemas/DatasetSummaryResponse"},{"type":"null"}],"description":"Optional dataset context for display (merged obs-derived fields and/or split-upload DEG counts)."},"results":{"anyOf":[{"items":{"$ref":"#/components/schemas/PredictionResultRow"},"type":"array"},{"type":"null"}],"title":"Results","description":"Prediction results for completed predictions. This is a preview of the primary target-score Parquet (e.g. target_score.parquet) and is capped server-side."},"source_influence_matrix":{"anyOf":[{"$ref":"#/components/schemas/SourceInfluenceMatrixPreview"},{"type":"null"}],"description":"When present next to the primary target-score Parquet in S3, a matrix preview of `{prefix}_source_influence_score.parquet` (same directory / prefix as the worker, or legacy `source_influence_score.parquet` next to `target_score.parquet`). For TwinCell, rows are typically protein targets and columns RNA sources. Capped by `max_source_influence_rows` and `max_columns` query params. Null if the file does not exist."},"artifacts":{"anyOf":[{"items":{"$ref":"#/components/schemas/PredictionArtifactItem"},"type":"array"},{"type":"null"}],"title":"Artifacts","description":"Optional outputs listed in callback metadata ``result_files`` as presigned download URLs (graphs, extra Parquet, etc.). Omitted for **external** ``target_validation`` jobs (no presigned URLs)."},"target_validation_score":{"anyOf":[{"$ref":"#/components/schemas/TargetValidationScoreRow"},{"type":"null"}],"description":"For **external** ``target_validation`` completed jobs: the single target-score row for ``prediction_metadata.target`` (``id``, ``percentage_degs_significant`` only). Other tiers use the ``results`` preview instead."},"causal_paths":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Causal Paths","description":"Deprecated for external ``target_validation`` jobs (always omitted). Use GET ``/v1/predictions/{id}/causal-paths`` for redacted paths for impacted DEGs (capped server-side). Internal users may still receive full ``causal_paths.parquet`` via ``artifacts`` when enabled."},"processing_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Step","description":"Latest worker-reported step from callback metadata (for example ``model_loaded``, ``results_uploaded``, ``causal_completed``). Omitted when not yet reported or for older predictions."},"progress_pct":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Progress Pct","description":"Approximate completion percentage from worker callbacks (0–100), when provided."}},"type":"object","required":["prediction_id","status","created_at","started_at","completed_at","error_message"],"title":"PredictionStatusResponse","description":"Prediction status and user-facing results.\n\nNote:\n    Internal processing metadata (including any S3 paths) is intentionally not\n    returned to clients."},"PredictionsListResponse":{"properties":{"predictions":{"items":{"$ref":"#/components/schemas/PredictionStatusResponse"},"type":"array","title":"Predictions"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor for next page."}},"type":"object","required":["predictions"],"title":"PredictionsListResponse","description":"Paginated list of predictions."},"SourceInfluenceMatrixPreview":{"properties":{"row_ids":{"items":{"type":"string"},"type":"array","title":"Row Ids","description":"Matrix row labels (source entity ids), aligned with `data`."},"column_ids":{"items":{"type":"string"},"type":"array","title":"Column Ids","description":"Matrix column labels (target feature ids), aligned with `data`."},"data":{"items":{"items":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"array"},"type":"array","title":"Data","description":"``data[i][j]`` is the score for ``row_ids[i]`` vs ``column_ids[j]``. ``null`` represents NaN in the Parquet file."},"truncated_rows":{"type":"boolean","title":"Truncated Rows","description":"True if the Parquet has more rows than returned (see `max_source_influence_rows` / server cap)."},"truncated_columns":{"type":"boolean","title":"Truncated Columns","description":"True if the Parquet has more columns than returned (see `max_columns` / server cap)."}},"type":"object","required":["row_ids","column_ids","data","truncated_rows","truncated_columns"],"title":"SourceInfluenceMatrixPreview","description":"Preview of the TwinCell source-influence score matrix (Parquet artifact).\n\nRows correspond to **sources** (e.g. ``STAT3|PROTEIN``); columns to **targets**\n(e.g. ``ACKR3|RNA``). Values are influence scores. Clients can rebuild a DataFrame\nwith ``pd.DataFrame(data, index=row_ids, columns=column_ids)`` and use\n``.loc['STAT3|PROTEIN']`` to pick a target column slice for thresholding before\ncausal analysis (``min_degs_fold_uniform`` when using fold-threshold source\nselection)."},"TargetValidationScoreRow":{"properties":{"id":{"type":"string","title":"Id","description":"Entity identifier (e.g. 'BRAF|PROTEIN')."},"percentage_degs_significant":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Percentage Degs Significant","description":"Percentage of significant DEGs for this target."}},"type":"object","required":["id"],"title":"TargetValidationScoreRow","description":"External target-validation score row (``GET /v1/predictions/{id}``).\n\nReturned in ``target_validation_score`` for non-internal users on completed\n``target_validation`` jobs. Exposes only the public subset of score fields."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"data-plane: predictions","description":"API-key authenticated prediction/inference endpoints. Use `X-API-Key: <api_key>`. Includes `POST/GET /predictions`, status polling, and completed-run artifact routes (`/mapped-degs`, `/degs-impacted`, `/causal-paths`, `/intermediary-proteins`, `/causal-graph`)."},{"name":"data-plane: causal-analysis","description":"API-key authenticated causal analysis endpoints. Use `X-API-Key: <api_key>`."}]}