All endpoints are under /api. Request and response bodies are JSON unless
stated. Errors return {"error": "...", "detail": "..."} with a 4xx/5xx status;
the UI shows error verbatim. That includes request-validation failures and
404s, which FastAPI and Starlette would otherwise answer in their own shapes.
Numeric fields are read with an explicit presence check, so an explicit 0
means zero rather than "use the default", and values outside their documented
range are refused rather than silently clamped.
A gaps entry on a path lists the step indices after which the join is a
scaffold gap (SPAdes' ;) rather than an edge in the graph.
The server holds exactly one project in memory.
{
"loaded": true,
"graph": {"segments": 10, "links": 9, "paths": 0, "total_length": 137400,
"components": 2, "dead_ends": 5, "has_sequences": true},
"source_path": "examples/demo/assembly.gfa",
"source_format": "gfa",
"reference": {"path": "...", "sequences": 2, "length": 169000},
"has_alignments": true,
"has_plan": false,
"align_backend": "mappy",
"blast_available": true,
"undo_depth": 0,
"settings": {"min_contig": 0, "circular_references": true,
"primary_only": true, "genome_size": null}
}reference is null when none is loaded.
Change the options that govern metrics and reference evaluation. Any subset may be given; unlisted keys are left alone. Returns the settings now in effect.
{"min_contig": 500, "circular_references": true, "primary_only": true,
"genome_size": null}| key | default | meaning |
|---|---|---|
min_contig |
0 |
ignore segments shorter than this in the statistics (500 matches QUAST) |
circular_references |
true |
treat reference sequences as circular, so a contig spanning a replicon's origin is not a relocation |
primary_only |
true |
exclude secondary alignments from the statistics, as QUAST does |
genome_size |
null |
expected genome size for NG50/NGA50; falls back to the reference length |
These are also reported under settings in GET /api/status, and may be passed
in the body of POST /api/reference to set them at the same time as aligning.
Body: {"path": "/abs/or/relative/path", "format": null}
format is one of gfa, gfa2, fastg, fasta, or null to sniff.
Returns the same shape as /api/status.
Body: {"path": "contigs.paths"} — attach SPAdes paths. Returns {"added": 12}.
Query params: min_length (int, default 0), max_nodes (int, default 15000),
component (int or omitted → all).
{
"segments": [
{"name": "ctg_1", "length": 19000, "depth": 31.2, "gc": 0.503,
"component": 0, "deg_start": 0, "deg_end": 1, "circular": false,
"ref_hits": [{"ref": "chromosome", "r_st": 0, "r_en": 19000,
"strand": 1, "identity": 0.9989, "q_st": 0, "q_en": 19000,
"mapq": 60, "is_primary": true, "q_len": 19000,
"r_len": 160000, "block_len": 19000}]}
],
"links": [{"from": "a", "from_orient": "+", "to": "b", "to_orient": "+", "overlap": 0}],
"paths": [{"name": "contig_1", "steps": ["1+", "2+", "4+"], "gaps": [1]}],
"truncated": false,
"shown": 10,
"total": 10,
"references": ["chromosome", "plasmid"]
}Link end convention (important for the renderer). Each segment is drawn as a
polyline with a start end and an end end. A link joins:
| from_orient | to_orient | joins |
|---|---|---|
+ |
+ |
A.end → B.start |
+ |
- |
A.end → B.end |
- |
+ |
A.start → B.start |
- |
- |
A.start → B.end |
Returns full detail including sequence (string) and neighbours.
Body:
{"path": "reference.fasta", "preset": "asm10", "min_identity": 0.0,
"min_length": 200, "threads": 8}preset ∈ asm5 | asm10 | asm20; anything else is a 400. min_identity
is a fraction in 0–1, not a percentage. Runs alignment (may take seconds), then
returns {"status": "...", "report": <reference report>, "metrics": <metrics>}.
Drops the reference and its alignments.
{
"metrics": { "num_contigs": 10, "total_length": 137400, "n50": 19000,
"l50": 3, "ng50": 13000, "gc_percent": 50.1, "auN": 20123.4,
"largest_contig": 32000, "num_links": 9, "num_components": 2,
"dead_ends": 5, "num_circular": 0, "mean_depth": 32.1,
"nx_curve": [[1, 32000], ...], "cumulative_curve": [[1, 32000], ...],
"length_histogram": [[1000, 3], ...] },
"reference": {
"genome_fraction": 82.06, "duplication_ratio": 1.0, "na50": 19000,
"nga50": 11500, "mismatches_per_100kb": 92.3, "indels_per_100kb": 0.0,
"num_misassemblies": 3, "num_relocations": 1, "num_inversions": 1,
"num_translocations": 1, "num_local_misassemblies": 0,
"unaligned_contigs": 1, "misassembled_contigs": ["ctg_x"],
"per_reference_coverage": {"chromosome": 84.1},
"coverage_blocks": {"chromosome": [[0, 19000], ...]},
"reference_sizes": {"chromosome": 22580},
"reference_length": 22580, "reference_sequences": 1,
"misassemblies": [{"contig": "ctg_x", "kind": "inversion",
"is_extensive": true, "contig_pos": 8000,
"description": "..."}]
}
}reference is null when no reference is loaded.
Body: {"op": "<name>", "args": {...}}. Returns
{"applied": "<name>", "count": 3, "graph": <status.graph>, "undo_depth": 1}.
| op | args |
|---|---|
delete |
{"names": ["a","b"]} |
filter |
{"min_length": 500, "min_depth": null, "max_depth": null, "keep_components": 5, "min_component_length": 0} |
simplify |
{} — merge unbranching chains |
break_misassemblies |
{"extensive_only": true} — needs a reference |
split |
{"name": "ctg_1", "positions": [5000]} |
merge |
{"steps": ["a+","b+"]} |
reverse |
{"name": "ctg_1"} |
Returns the same shape as /api/op.
Body:
{"method": "reference", "min_identity": 0.8, "min_query_coverage": 0.3,
"min_align_length": 500, "min_gap": 100, "fill_gaps_from_graph": true,
"include_unplaced": true, "break_misassemblies_first": false}method ∈ reference | graph. Returns {"plan": <plan>, "preview": <built stats>}.
Plan shape:
{"method": "reference", "scaffold_count": 3, "placed_count": 10,
"record_count": 14,
"unplaced": ["ctg_foreign"], "redundant": [], "notes": ["..."],
"scaffolds": [
{"name": "scaffold_chromosome", "source": "reference", "reference": "chromosome",
"members": [{"segment": "ctg_1", "orientation": "+", "gap_after": 3000,
"gap_evidence": "reference", "bridge_path": ["r+"],
"bridge_sequence_length": 2400, "ref": "chromosome",
"ref_start": 0, "ref_end": 19000, "identity": 0.9989,
"overlaps_previous": false, "trim_next": 0}]}
]}gap_evidence ∈ reference | graph | adjacent | manual | default.
scaffold_count and placed_count count only scaffolds that join something:
with include_unplaced (the default) every unplaced contig is also carried
through as its own single-member scaffold, and counting those as placed made
the two numbers contradict each other. record_count is how many records the
export will write, i.e. scaffolds plus pass-throughs.
trim_next is how many bases the following member gives up because they are
shared with this one — set only where the two contig ends were checked to match
base for base.
Returns {"plan": ..., "preview": ...}.
preview:
{"scaffold_count": 3, "total_length": 182904, "gap_bases": 43104,
"bridged_bases": 2400, "num_gaps": 4, "n50": 175404, "largest": 175404,
"warnings": []}Body: {"query": "ACGT... or a path to a FASTA", "min_identity": 0.8}
Returns {"backend": "blast"|"minimap2", "hits": [{"segment": "ctg_1", "identity": 0.99, "q_st": 0, "q_en": 500, "s_st": 100, "s_en": 600, "strand": 1, "bitscore": 900}]}
Body: {"outdir": "plastr_out", "what": ["scaffolds","agp","gfa","csv","report","session"], "overwrite": false}
Returns {"written": [{"kind": "scaffolds", "path": "...", "bytes": 1234}]}.
overwrite defaults to false: an export that would replace an existing file
fails with 400 rather than destroying it. scaffolds and agp are skipped
when no plan has been built, so compare what against the kinds in written
rather than assuming everything asked for was produced.
Streams a single artefact directly (scaffolds, agp, gfa, csv, report,
session). Content-Disposition is set so the browser saves it.
Save/restore {"layout": {...}, "settings": {...}, "plan": {...}}. The server
stores layout and settings opaquely — they are the renderer's business.
Directory listing for the built-in file picker:
{"path": "/abs", "parent": "/", "entries": [{"name": "x.gfa", "is_dir": false, "size": 123}]}