App API
This page documents HTTP endpoints exposed by an installed SeqDesk instance — the in-app API surface, as opposed to the public seqdesk.com endpoints covered by the Pipeline API. Most are used by the SeqDesk UI itself, but they are stable enough to call from automation, scripts, or external tools.
All endpoints live under /api/ on your SeqDesk host. Authentication uses
the standard NextAuth session cookie unless noted. The pipeline weblog is the
main exception — it is authenticated by a shared secret, not a session.
Form schemas
The dynamic form configuration is exposed read-only so external tooling can mirror the same field set the SeqDesk UI renders.
GET /api/form-schema
Returns the order-form schema as configured by the facility admin in the Order Form Builder.
{
"fields": [ { "id": "...", "name": "library_strategy", "type": "select", "options": [...], "required": true, "groupId": "..." } ],
"groups": [ { "id": "group_sequencing", "name": "Sequencing Information", "icon": "Dna", "order": 1 } ],
"version": "2026-04-01T00:00:00Z",
"enabledMixsChecklists": ["ERC000022"],
"perSampleFields": ["sample_name", "barcode"]
}The response is filtered by the caller’s role: facility-admin-only fields are omitted for researchers.
GET /api/study-form-schema
Same shape, but for the study metadata form. Includes additional studyFields
and modules keys describing study-level vs. sample-level fields and which
modules’ fields are currently enabled.
MIxS checklists
MIxS is the GSC’s Minimum Information about a Sequence checklist standard. SeqDesk ships checklist definitions and field templates; admins enable specific checklists through the form builder, and researchers see the corresponding required fields when filling out study metadata.
GET /api/mixs-checklists
List all available checklists.
curl https://your-host/api/mixs-checklists{
"checklists": [
{
"name": "soil",
"file": "soil-checklist.json",
"fieldCount": 53,
"mandatoryCount": 12,
"accession": "ERC000022"
}
],
"total": 16
}Single-checklist lookup with ?accession= or ?name=:
curl https://your-host/api/mixs-checklists?accession=ERC000022Returns the full checklist definition including every field, its data type, unit options, MIxS section, and whether it is mandatory.
GET /api/mixs-templates
The same field definitions but in template form, ready to be embedded in the
form builder. ?name=<checklist> returns templates for one checklist.
Pipeline weblog
Nextflow runs are configured to POST execution events to the SeqDesk weblog endpoint. The endpoint also accepts events from other pipeline-runtime adapters (SLURM trace, queue updates, internal step events). See Pipeline Runtime for the client-side configuration.
POST /api/pipelines/weblog?runId=<id>&token=<secret>
Each call records one PipelineRunEvent. The target run is identified by the
runId query parameter, and the call is authenticated by the shared
weblog secret passed as the token query parameter — there is no session
cookie and no runId in the body.
| Condition | Status |
|---|---|
| No weblog secret configured on the instance | 503 |
token does not match the configured secret | 403 |
Missing runId | 400 |
Unknown runId | 404 |
The weblog secret is configured under Admin → Application Settings →
Pipeline execution; until it is set the endpoint fails closed (503) so the
state-mutating webhook is never left unauthenticated.
The JSON body is the Nextflow -with-weblog payload (or another adapter’s
event). SeqDesk reads the event type from event / eventType / type and
the process/trace details from trace (or task):
curl -X POST "https://your-host/api/pipelines/weblog?runId=ckxx...&token=$WEBLOG_SECRET" \
-H "Content-Type: application/json" \
-d '{
"event": "process_completed",
"trace": { "process": "MAG:ASSEMBLY:MEGAHIT", "status": "COMPLETED", "exit": 0,
"duration": "00:43:12", "%cpu": "812", "rss": "12.3 GB" }
}'On success the endpoint returns { "success": true }.
Event types and sources
The source field categorizes where an event came from. Recognized values:
| Source | Meaning |
|---|---|
weblog | Nextflow -with-weblog payload |
trace | Parsed .nextflow/trace.txt row |
queue | SLURM queue poller (e.g., a step transitioned PD → R) |
process | Internal SeqDesk step lifecycle event |
Common eventType values include run_started, run_completed,
process_submitted, process_started, process_completed,
process_failed. Anything ingested without a recognized type is still stored
verbatim — the server does not gate-keep on the value, so custom adapters can
add their own.
Multipart upload flow
The order page uses a chunked upload protocol when reads or other artifacts
are attached to a sample. These endpoints are FACILITY_ADMIN-only. Build
automation that mimics the same flow when bulk-loading data.
POST /api/orders/[id]/sequencing/uploads
Initiate an upload session. targetKind is read or artifact; for read
uploads targetRole must be R1 or R2, and the filename must use an allowed
sequencing-file extension.
{
"targetKind": "read",
"targetRole": "R1",
"originalName": "S1_R1.fastq.gz",
"expectedSize": 1843921023,
"checksumProvided": "6f1b...",
"mimeType": "application/gzip",
"sampleId": "smpl_...",
"metadata": { "dataClass": "raw" }
}targetKind, targetRole, originalName, and expectedSize are required
(400 otherwise). Response:
{
"success": true,
"uploadId": "upl_...",
"tempPath": "orders/.../.tmp/upl_.../S1_R1.fastq.gz",
"status": "PENDING",
"receivedSize": 0
}Stream chunks to tempPath (relative to the configured data base path). When
the file is fully written, call complete.
POST /api/orders/[id]/sequencing/uploads/[uploadId]/complete
Takes no body. Returns { "success": true, ... } with the finalized upload
fields. If checksumProvided was supplied at initiate, the complete call
verifies the computed checksum against it before promoting the file out of
.tmp.
File operations
These endpoints back the in-app file browser and assembly downloader. They
respect demo-session restrictions (Demo mode)
and the allowUserAssemblyDownload setting.
GET /api/files/download?path=<rel>
Streams a file. Path is resolved relative to the configured data base path
and validated against directory traversal. Demo sessions get 403.
GET /api/files/preview?path=<rel>
Serves an HTML report (e.g., FastQC, MultiQC) inline with strict CSP headers. Useful for embedding QC reports in the SeqDesk UI without downloading.
POST /api/files/checksum
FACILITY_ADMIN-only. Computes MD5 for a list of paths (max 50) and updates the
Read record (if any) for each. Checksums are returned as raw lowercase hex
(no md5: prefix). Useful as a one-shot integrity audit.
// Request
{ "filePaths": ["orders/abc/S1_R1.fastq.gz", "orders/abc/S1_R2.fastq.gz"] }
// Response
{
"success": true,
"results": [
{ "filePath": "orders/abc/S1_R1.fastq.gz", "checksum": "6f1b...", "updatedReadRecord": true }
],
"summary": { "total": 2, "successful": 2, "failed": 0, "updatedReadRecords": 2, "notLinkedToRead": 0 }
}POST /api/files/delete
Bulk-delete a list of paths. Removes the file from disk and clears any
referencing Read records. Idempotent on already-deleted entries.
Sequencing run import
POST /api/orders/[id]/sequencing/runs/import
FACILITY_ADMIN-only. Accepts a multipart form with an Excel attachment
(file) describing a run plan — one row per (runId, sampleCode, barcode).
Used by the “Import run plan” button on the sequencing tab of the order detail
page. (CSV is not accepted; the body is parsed with ExcelJS.)
This is a two-phase flow. Without ?apply=true the endpoint returns a preview
only — it never mutates state:
{
"sheet": "Run Samples",
"rows": [ { "rowNumber": 2, "runId": "RUN-2026-04-30-001", "sampleCode": "S1", "barcode": "BC01", "customFields": {}, "unmapped": {} } ],
"rowCount": 1,
"unmappedColumns": ["Notes"],
"missingSamples": ["S99"],
"duplicateBarcodes": [ { "runId": "RUN-2026-04-30-001", "barcode": "BC01", "count": 2 } ],
"rowErrors": [ { "rowNumber": 7, "message": "Sample not found on this order: S99" } ],
"applyReady": false
}applyReady is true only when there is at least one row and rowErrors is
empty. With ?apply=true and a clean preview, the endpoint upserts
SequencingRun and SequencingRunSample rows and returns the same preview
fields plus:
{
"success": true,
"createdOrUpdated": [ { "runId": "RUN-2026-04-30-001", "assignments": 2 } ]
}If apply=true is sent while rowErrors is non-empty, the endpoint returns
400 with the preview echoed alongside the error.
Pipeline run control
These endpoints operate on a single PipelineRun ([id]). Except where noted
they are FACILITY_ADMIN-only and disabled in the public demo.
POST /api/pipelines/runs/[id]/start
Stages and launches a run. Accepts an optional JSON body of start options
(empty body allowed). Returns the launcher result body with its own status
code (e.g. 200/202 on success, error status otherwise).
POST /api/pipelines/runs/[id]/sync
Reconciles a run’s status against its execution backend (SLURM/local queue and
on-disk outputs). Authenticated by session: a FACILITY_ADMIN or a researcher
who owns the run’s target may call it. Returns the sync result body.
PUT /api/pipelines/runs/[id]/selection
Marks a completed run as the final selected result for its
study/order + pipeline target (upserts a PipelineResultSelection). Returns
{ "success": true, "selection": { ... } }. Returns 400 if the run is not
completed or has no study/order target.
DELETE /api/pipelines/runs/[id]/selection
Clears the selection for that run’s target. Returns
{ "success": true, "cleared": <bool> }.
POST /api/pipelines/runs/[id]/resolve-outputs
Re-discovers outputs for a completed or failed run and writes the resulting
Assembly/Bin/PipelineArtifact records. Requires runFolder to be set and
the target to have samples.
{
"success": true,
"discovered": { "...": "adapter summary" },
"resolved": { "assembliesCreated": 1, "binsCreated": 12, "artifactsCreated": 4 },
"errors": [],
"warnings": []
}GET /api/pipelines/runs/[id]/cleaned-reads
Lists the cleaned-read candidates produced by a read-cleaning run, for the admin review/promotion flow. Returns a candidate summary.
POST /api/pipelines/runs/[id]/cleaned-reads
Promotes selected cleaned-read candidates into canonical Read records.
Optional body { "sampleIds": ["..."] } limits promotion to specific samples;
omit it to promote all. Returns { "success": true, ... }.
GET /api/pipelines/runs/[id]/pending-writebacks
Lists the pending result writebacks for an order-targeted run — the read candidates and report files an admin can promote. Returns:
{
"run": { "id": "...", "runNumber": "...", "pipelineId": "...", "status": "...", "orderId": "..." },
"readCandidates": [ { "artifactId": "...", "outputId": "...", "sampleId": "...", "sampleCode": "S1",
"file1": "...", "file2": null, "targetDataClass": "cleaned",
"status": "candidate", "currentRead": { "id": "...", "dataClass": "raw", "isProtectedRaw": true } } ],
"reports": [ { "id": "...", "name": "multiqc_report.html", "path": "...", "outputId": "..." } ],
"review": { "...": "UI copy" }
}POST /api/pipelines/runs/[id]/pending-writebacks
Promotes the pending writebacks (the candidate reads/reports above) into
canonical records. Optional body { "sampleIds": ["..."] } scopes the
promotion; omit to promote all. Returns the promotion result.
Live stream (MinKNOW ingest)
These endpoints back the live ONT stream-ingest subsystem. They are
FACILITY_ADMIN-only (the read endpoints accept a facility-admin read
session). See the stream data models.
GET /api/orders/[id]/stream
Lists the order’s stream runs (most recent first, up to 50) with their latest
event. totalBases is serialized as a string (BigInt).
POST /api/orders/[id]/stream
Starts a stream run watching outputDir (required; validated to live under the
configured MinKNOW output root). Optional deviceId, flowCellId,
minknowRunId, and a barcodeMap object. Only one ACTIVE run may watch a
given directory — a conflicting start returns 409; an invalid outputDir
returns 400.
GET /api/orders/[id]/stream/[streamRunId]/events
Cursor-paginated event feed. Without a cursor it returns the newest events
(live-tail); with ?after=<seq> it pages forward oldest-first. ?limit=<n> is
clamped to [1, 500] (default 100). Response:
{
"events": [ { "id": "...", "seq": 42, "ts": "2026-05-01T10:00:00.000Z", "kind": "FILE_INGESTED", "payload": { "...": "..." } } ],
"cursor": 42
}Advance your client cursor to the returned cursor to resume without dropping
events.
POST /api/orders/[id]/stream/[streamRunId]/stop
Stops a stream run. Returns { "ok": true }, or { "ok": true, "alreadyStopped": true } /
{ "ok": true, "alreadyStopping": true } if it was already in a terminal/stopping state.
GET /api/orders/[id]/stream/[streamRunId]/by-barcode
Aggregates the run’s FILE_INGESTED events by barcode. Response:
{
"barcodes": [
{ "barcode": "barcode01", "fileCount": 12, "totalSize": 1048576, "totalReads": 4000,
"totalBases": 1200000, "lastFileAt": "2026-05-01T10:05:00.000Z", "lastFilePath": "..." }
]
}Conventions
- All POST endpoints accept
application/jsonunless they explicitly take a multipart body (the run import and uploads are the main exceptions). - Errors return
{ "error": "<message>" }with an appropriate 4xx/5xx status. - Sequencing data management (uploads, run-plan import, checksums) and pipeline
control (start, selection, resolve-outputs, cleaned-reads, pending-writebacks)
require
FACILITY_ADMIN. Read-only run endpoints (e.g. runsync) also admit a researcher who owns the run’s target. The weblog uses a shared secret rather than a session. - Pagination uses
?cursor=<id>&limit=<n>(the stream events feed uses?after=<seq>&limit=<n>) where supported.