Expression search¶
With the Expression search API, you can submit a search, poll its progress and download the results and cell data, without touching the browser.
A search always follows the same pattern:
POST /api/expression/submitreturns asearch_job_id.- Poll
GET /api/expression/status/<search_job_id>until the status iscompleted. GET /api/expression/results/<search_job_id>returns the expression data.
Endpoints¶
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/expression/submit |
Required | Submit a search query |
| GET | /api/expression/status/<search_job_id> |
Required | Poll search progress |
| GET | /api/expression/results/<search_job_id> |
Required | Expression results |
| GET | /api/expression/filter-options/<search_job_id> |
Required | Cell types present in a result |
| GET | /api/expression/results/<search_job_id>/cells/info |
Required | Cells summary, datasets, whitelists |
| GET | /api/expression/results/<search_job_id>/cells |
Required | Cell IDs and barcodes per sample |
| POST | /api/expression/results/<search_job_id>/cells/download |
Required | ZIP archive of cell data |
| POST | /api/expression/all-cells-download |
Required | Bulk cells table as gzip TSV |
| POST | /api/expression/cell-expression-export |
Required | Queue a per-cell matrix export |
| GET | /api/expression/cell-expression-export/<export_id> |
Required | Export status |
| GET | /api/expression/cell-expression-export/<export_id>/download |
Required | Export ZIP |
| POST | /api/expression/interpret |
Required | Ask the LLM to interpret a prompt |
| GET | /api/expression/interpret/<task_id> |
Required | Poll the interpretation task |
| POST | /api/expression/sample-metadata |
Required | Metadata for a set of sample IDs |
| GET | /api/expression/quota |
Required | Remaining daily quota |
| GET | /api/expression/datasets |
Public | List datasets |
| POST | /api/expression/search-context-rows |
Public | Server-side result table rows |
| POST | /api/expression/suggestions |
Public | Typo-tolerant query suggestions |
Submit a search¶
curl -X POST https://malva.mdc-berlin.de/api/expression/submit \
-H "Authorization: Bearer malva_..." \
-H "Content-Type: application/json" \
-d '{"query": "CD3E MS4A1"}'
Request body:
| Field | Type | Description |
|---|---|---|
query |
string | Required. Gene names, a FASTA sequence, or a natural-language query such as T cells in lung |
dataset_ids |
array of int | Optional. Restrict the search to specific datasets |
count_at_least |
int | Optional. Lower bound on cell count |
count_at_most |
int | Optional. Upper bound on cell count |
unstranded |
bool | Optional. Treat sequences as unstranded |
Response:
{
"job_id": "local-job-uuid",
"search_job_id": "search-job-uuid",
"status": "running",
"searches_remaining": 48
}
The query can contain up to 10 FASTA sequences of up to 10,000 base pairs
each. Longer entries are truncated. Each submission consumes one unit of your
daily quota. When the quota is exhausted the endpoint returns 429 with
quota_exceeded.
Poll the status¶
curl https://malva.mdc-berlin.de/api/expression/status/<search_job_id> \
-H "Authorization: Bearer malva_..."
Poll every few seconds until status is completed. If the search service
rejects the query, the status becomes error.
Read the results¶
curl https://malva.mdc-berlin.de/api/expression/results/<search_job_id> \
-H "Authorization: Bearer malva_..."
{
"status": "completed",
"genes": {
"CD3E": {
"ncells": 15342,
"expression_data": {"samples": [...], "cell_types": [...], "data": [...]},
"sequence": "ACGT...",
"sequence_length": 300
}
}
}
genes maps each searched sequence to its expression data. The
expression_data object contains the samples and cell types that matched, and
the compact expression table that the web interface renders. This is the same
data that drives the results table, so the same display
modes apply: relative expression, fraction
expressing, raw kmer hits and cell count.
Cell data¶
Cells summary¶
curl https://malva.mdc-berlin.de/api/expression/results/<search_job_id>/cells/info \
-H "Authorization: Bearer malva_..."
Returns {total_cells, dataset_ids, has_whitelists, samples} where samples
maps each sample ID to {n_cells, dataset_id, protocol, whitelist_id,
whitelist_type}.
Cell IDs and barcodes¶
curl "https://malva.mdc-berlin.de/api/expression/results/<search_job_id>/cells?sample_ids=1,2&barcodes=1" \
-H "Authorization: Bearer malva_..."
Returns {has_whitelists, samples} where each sample maps to
{cell_ids, barcodes}. This is the endpoint the malva_client package uses
to fetch the exact cell set of a search.
Cell data archive¶
curl -X POST https://malva.mdc-berlin.de/api/expression/results/<search_job_id>/cells/download \
-H "Authorization: Bearer malva_..." \
-H "Content-Type: application/json" \
-d '{"sample_ids": [1, 2], "include_barcodes": true}'
Returns a ZIP archive (malva_cells_<id>_<ts>.zip) with a MANIFEST.txt and
gzipped TSV files for cell IDs, barcodes, normalization factors, sample and
cell type summaries, and sample metadata.
Bulk download¶
curl -X POST https://malva.mdc-berlin.de/api/expression/all-cells-download \
-H "Authorization: Bearer malva_..." \
-H "Content-Type: application/json" \
-d '{"sample_ids": [1, 2, 3]}'
Returns a gzip-compressed TSV (malva_all_cells_<ts>.tsv.gz) with the columns
sample_id, cell_id, cell_type, total_counts. Accepts at most 50 sample IDs.
Per-cell expression matrix¶
curl -X POST https://malva.mdc-berlin.de/api/expression/cell-expression-export \
-H "Authorization: Bearer malva_..." \
-H "Content-Type: application/json" \
-d '{"items": [{"job_id": "search-job-uuid", "feature": "CD3E"}], "sample_ids": [1, 2]}'
The request queues an export on the search service and returns an export_id.
Poll GET /api/expression/cell-expression-export/<export_id> until the export
is ready, then stream the ZIP with
GET /api/expression/cell-expression-export/<export_id>/download.
Query interpretation¶
POST /api/expression/interpret sends a natural-language prompt to the LLM
service and returns a task_id. Poll
GET /api/expression/interpret/<task_id> until the status is completed;
the response contains the reformatted query, the extracted entities and the
query type. This is the same engine that powers query interpretation in the
web interface.
Sample metadata¶
curl -X POST https://malva.mdc-berlin.de/api/expression/sample-metadata \
-H "Authorization: Bearer malva_..." \
-H "Content-Type: application/json" \
-d '{"ids": [1, 2, 3]}'
{
"metadata": {
"1": {"organ": "lung", "disease": "COVID-19"},
"2": {"organ": "lung", "disease": "control"}
}
}
Quota¶
GET /api/expression/quota returns {can_search, searches_remaining,
account_type}. See Quotas and limits for what
the numbers mean.