{"components":{"parameters":{"IdempotencyKey":{"description":"Opaque string. If supplied, the server caches the response for 24 hours and returns the cached body on retry. Reusing the same key with a different body yields a 409.","in":"header","name":"Idempotency-Key","required":false,"schema":{"maxLength":200,"type":"string"}},"JobId":{"description":"UUID of the job.","in":"path","name":"job_id","required":true,"schema":{"format":"uuid","type":"string"}},"Page":{"in":"query","name":"page","schema":{"default":1,"minimum":1,"type":"integer"}},"PerPage":{"in":"query","name":"per_page","schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}}},"schemas":{"Artifact":{"properties":{"mime":{"type":"string"},"name":{"type":"string"},"size_bytes":{"type":"integer"},"url":{"type":"string"}},"type":"object"},"CreateJobRequest":{"example":{"alignment_method":"mafft","input_type":"pasted_sequence","notes":"API test with valid pasted FASTA","sequence":">Sample_A\nATGCGTACGTAGCTAGCTAGCTAGCTAGCTAACGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCG\n>Sample_B\nATGCGTACGTAGCTAGCTAGCTAGCTAGCTAACGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGTTTGATCGATCGATCG\n>Sample_C\nATGCGTACGTAGCTAGCTAGCTAGCTAGCTAACGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGATCGTTTGATCG\n>Sample_D\nATGCGTACGTAGCTAGCTAGCTAGCTAGCTAACGATCGATCGATCGATCGATCGATCGATCGATCGATCGTTTGATCGATCGATCGATCGATCG","tree_method":"fasttree","trim_terminal_overhangs":true,"trimming_method":"trimal_gappy"},"properties":{"accessions":{"description":"List of GenBank accession numbers. Max 500 entries, 64 chars each.","items":{"maxLength":64,"type":"string"},"maxItems":500,"type":"array"},"alignment_method":{"default":"mafft","enum":["mafft","muscle","clustalo","iqtree_builtin","default"],"type":"string"},"alrt_replicates":{"default":1000,"description":"IQ-TREE SH-aLRT replicates, run alongside Ultrafast Bootstrap. Nodes are labelled SH-aLRT/UFBoot. 0 reports UFBoot only.","maximum":10000,"minimum":0,"type":"integer"},"bootstrap":{"default":1000,"maximum":10000,"minimum":0,"type":"integer"},"input_type":{"default":"pasted_sequence","description":"How sequence data is provided. Use `pasted_sequence` with FASTA text in the `sequence` field, or `accession_list` with GenBank IDs in `accessions`. If `sequence` is non-empty and `input_type` is omitted, it defaults to `pasted_sequence`. Server-side FASTA file uploads are not supported via this endpoint.","enum":["pasted_sequence","accession_list"],"type":"string"},"mcmc_burnin_fraction":{"default":0.25,"description":"Relative fraction of MCMC samples discarded as burn-in.","maximum":0.99,"minimum":0,"type":"number"},"mcmc_generations":{"default":50000,"maximum":100000000,"minimum":1000,"type":"integer"},"mcmc_nchains":{"default":4,"maximum":16,"minimum":1,"type":"integer"},"mcmc_nruns":{"default":2,"maximum":8,"minimum":1,"type":"integer"},"notes":{"maxLength":2000,"type":"string"},"sequence":{"description":"FASTA-formatted sequence text for `pasted_sequence` jobs. One or more `>header\\nbases` records pasted directly into the request body. Use real DNA bases, not placeholders. Max 5 MB; the overall request body is capped at 16 MB (413 returned beyond that).","example":">Sample_A\nATGCGTACGTAGCTAGCTAGCTA\n>Sample_B\nATGCGTACGTAGCTAGCTAGCTA","maxLength":5000000,"type":"string"},"tree_method":{"enum":["nj","raxml","iqtree","mrbayes","fasttree"],"type":"string"},"tree_model":{"description":"Substitution model. When omitted, tree_method=iqtree runs ModelFinder (-m MFP) to select the best-fit model by BIC; other maximum-likelihood methods use the server's DEFAULT_ML_MODEL (normally GTR+G). The chosen IQ-TREE model is reported as model_selected in tree_metadata.json. Pass an explicit model name to fix it.","type":"string"},"trim_terminal_overhangs":{"default":true,"description":"Trim alignment columns outside the common covered span before tree building.","type":"boolean"},"trimming_method":{"default":"trimal_gappy","description":"Alignment trimmer. 'trimal_gappy' (default) runs trimAl -gt 0.9, dropping columns that are >90%% gaps. 'trimal' runs -automated1, which is aggressive and strips much of ITS1/ITS2 -- not recommended for ITS.","enum":["none","trimal_gappy","trimal","bmge"],"type":"string"}},"type":"object"},"Error":{"properties":{"error":{"properties":{"code":{"example":"validation_failed","type":"string"},"details":{"type":"object"},"message":{"type":"string"},"request_id":{"example":"a1b2c3d4e5f6","type":"string"}},"required":["code","message","request_id"],"type":"object"}},"required":["error"],"type":"object"},"HealthStatus":{"properties":{"api_version":{"example":"v1","type":"string"},"status":{"example":"ok","type":"string"}},"type":"object"},"Job":{"properties":{"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"input_type":{"type":"string"},"links":{"properties":{"events":{"type":"string"},"files":{"type":"string"},"self":{"type":"string"},"view":{"type":"string"}},"type":"object"},"metrics":{"type":"object"},"notes":{"type":"string"},"params":{"properties":{"alignment_method":{"type":"string"},"alrt_replicates":{"type":"integer"},"bootstrap":{"type":"integer"},"mcmc_burnin_fraction":{"type":"number"},"mcmc_generations":{"type":"integer"},"mcmc_nchains":{"type":"integer"},"mcmc_nruns":{"type":"integer"},"tree_method":{"type":"string"},"tree_model":{"type":"string"},"trimming_method":{"type":"string"}},"type":"object"},"status":{"enum":["queued","running","completed","failed","error"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"RecomputeRequest":{"additionalProperties":false,"description":"Override stored job parameters and re-run the pipeline on the same input data. Only the fields listed here may be overridden; unknown keys are rejected with 422. To submit different input data, create a new job with POST /jobs.","properties":{"alignment_method":{"enum":["mafft","muscle","clustalo","iqtree_builtin","default"],"type":"string"},"alrt_replicates":{"description":"IQ-TREE SH-aLRT replicates. 0 reports UFBoot only.","maximum":10000,"minimum":0,"type":"integer"},"bootstrap":{"maximum":10000,"minimum":0,"type":"integer"},"mcmc_burnin_fraction":{"default":0.25,"description":"Relative fraction of MCMC samples discarded as burn-in.","maximum":0.99,"minimum":0,"type":"number"},"mcmc_generations":{"maximum":100000000,"minimum":1000,"type":"integer"},"mcmc_nchains":{"maximum":16,"minimum":1,"type":"integer"},"mcmc_nruns":{"maximum":8,"minimum":1,"type":"integer"},"notes":{"maxLength":2000,"type":"string"},"outgroup":{"maxLength":256,"type":"string"},"tree_method":{"enum":["nj","raxml","iqtree","mrbayes","fasttree"],"type":"string"},"tree_model":{"maxLength":64,"type":"string"},"trim_terminal_overhangs":{"default":true,"description":"Trim alignment columns outside the common covered span before tree building.","type":"boolean"},"trimming_method":{"enum":["none","trimal_gappy","trimal","bmge"],"type":"string"}},"type":"object"},"Token":{"properties":{"created_at":{"format":"date-time","type":"string"},"id":{"type":"integer"},"last_used_at":{"format":"date-time","nullable":true,"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"revoked_at":{"format":"date-time","nullable":true,"type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"User":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"format":"email","type":"string"},"id":{"type":"integer"}},"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"dikarya_<base64url>","description":"Provide an API token via `Authorization: Bearer dikarya_...`.\n\n**Available scopes**:\n- `jobs:read`: list/get jobs, read events, download files & logs\n- `jobs:write`: create, recompute, mutate, delete jobs\n- `tools:read`: BLAST, GenBank, MycoMap, iNaturalist lookups\n- `account:read`: `/me` and list own tokens","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"Dikarya","url":"https://dikarya.us"},"description":"Public API for Dikarya. All endpoints under `/api/v1` require a bearer token; mint one at `/user/tokens`. Tokens are scoped; see the Authentication section below.","title":"Dikarya Public API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/health":{"get":{"description":"No authentication required. Returns `{status, api_version}`.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/HealthStatus"}},"type":"object"}}},"description":"OK"}},"security":[],"summary":"Liveness ping","tags":["Health"]}},"/jobs":{"get":{"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"since","schema":{"format":"date-time","type":"string"}},{"in":"query","name":"until","schema":{"format":"date-time","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Job"},"type":"array"},"meta":{"properties":{"has_next":{"type":"boolean"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}},"type":"object"}},"type":"object"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"List your jobs","tags":["Jobs"]},"post":{"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/Job"}},"type":"object"}}},"description":"Queued"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Conflict (Idempotency-Key reused with different body, or request still in flight)"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Create a new phylogenetic job","tags":["Jobs"]}},"/jobs/{job_id}":{"delete":{"responses":{"200":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Delete a job and its files","tags":["Jobs"]},"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/Job"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"Get a job by id","tags":["Jobs"]},"parameters":[{"$ref":"#/components/parameters/JobId"}]},"/jobs/{job_id}/events":{"get":{"description":"Returns `text/event-stream`. Emits a `snapshot` event first, then live `data:` updates, with 15-second pings. A single token may hold at most 5 concurrent streams (429 `too_many_streams` beyond that). Each connection is hard-capped at 30 minutes; on timeout the server emits `event: timeout` and closes. Clients should reconnect. If the token is revoked mid-stream, the server emits `event: revoked` and closes.","parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"content":{"text/event-stream":{}},"description":"Event stream"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"SSE stream of pipeline progress","tags":["Jobs"]}},"/jobs/{job_id}/files":{"get":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Artifact"},"type":"array"},"meta":{"properties":{"has_next":{"type":"boolean"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}},"type":"object"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"List downloadable artifacts","tags":["Jobs"]}},"/jobs/{job_id}/files/{name}":{"get":{"description":"`name` must be one of the allowlisted artifact names returned by `/jobs/{id}/files` (e.g. `tree.newick`, `alignment.fasta`).","parameters":[{"$ref":"#/components/parameters/JobId"},{"in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File bytes"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"Download a job artifact","tags":["Jobs"]}},"/jobs/{job_id}/logs/{log_name}":{"get":{"parameters":[{"$ref":"#/components/parameters/JobId"},{"in":"path","name":"log_name","required":true,"schema":{"enum":["pipeline","alignment","tree_builder"],"type":"string"}}],"responses":{"200":{"description":"Log text"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"security":[{"bearerAuth":["jobs:read"]}],"summary":"Fetch a job log","tags":["Jobs"]}},"/jobs/{job_id}/recompute":{"post":{"parameters":[{"$ref":"#/components/parameters/JobId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecomputeRequest"}}},"required":false},"responses":{"202":{"description":"Queued"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Conflict (Idempotency-Key reused with different body, or request still in flight)"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Re-run the pipeline with new params","tags":["Jobs"]}},"/jobs/{job_id}/tree/midpoint_root":{"post":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"Updated tree state"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Apply midpoint rooting","tags":["Tree"]}},"/jobs/{job_id}/tree/prune":{"post":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"tips":{"description":"Tip names (or internal-node names) to remove. Max 10 000 entries; each name max 256 chars.","items":{"maxLength":256,"minLength":1,"type":"string"},"maxItems":10000,"minItems":1,"type":"array"}},"required":["tips"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Updated tree state"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Remove tips from the tree","tags":["Tree"]}},"/jobs/{job_id}/tree/rename":{"post":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"new_name":{"description":"May not contain Newick-unsafe characters: ()[],:;'\"\\t\\n\\r","maxLength":256,"minLength":1,"type":"string"},"old_name":{"maxLength":256,"minLength":1,"type":"string"}},"required":["old_name","new_name"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Updated tree state"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Rename a tip","tags":["Tree"]}},"/jobs/{job_id}/tree/reroot":{"post":{"parameters":[{"$ref":"#/components/parameters/JobId"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"outgroup":{"maxLength":256,"minLength":1,"type":"string"}},"required":["outgroup"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Updated tree state"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Reroot using an outgroup","tags":["Tree"]}},"/me":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/User"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"}},"security":[{"bearerAuth":["account:read"]}],"summary":"Get the current user","tags":["Account"]}},"/tokens":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Token"},"type":"array"},"meta":{"properties":{"has_next":{"type":"boolean"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}},"type":"object"}},"type":"object"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"}},"security":[{"bearerAuth":["account:read"]}],"summary":"List your API tokens (no secrets)","tags":["Account"]}},"/tools/blast":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"max_sequences":{"default":50,"description":"Values outside this range are clamped, not rejected.","maximum":500,"minimum":1,"type":"integer"},"min_identity":{"default":90.0,"description":"Values outside this range are clamped, not rejected.","maximum":100,"minimum":50,"type":"number"},"query":{"description":"FASTA sequence or GenBank accession. NCBI rejects very long queries; the per-call cap is 50 000 chars.","maxLength":50000,"type":"string"}},"required":["query"],"type":"object"}}},"required":true},"responses":{"200":{"description":"BLAST results"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body exceeds the 16 MB global limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["tools:read"]}],"summary":"Run BLAST on a sequence or accession","tags":["Tools"]}},"/tools/genbank":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"accessions":{"description":"Comma/space-separated list, or array of accession strings. Max 200 accessions per call.","oneOf":[{"maxLength":64000,"type":"string"},{"items":{"maxLength":64,"type":"string"},"maxItems":200,"type":"array"}]}},"type":"object"}}},"required":true},"responses":{"200":{"description":"Fetched sequences"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["tools:read"]}],"summary":"Fetch FASTA for GenBank accessions","tags":["Tools"]}},"/tools/inaturalist-tree":{"post":{"description":"Reads the observation's `Mycomap BLAST Results` observation field, refreshes the MycoMap local BLAST results, builds a one-click Dikarya tree from that URL, and when the job completes writes a `Phylogenetic Tree` field back to the observation with the public tree viewer URL. The write uses the site-wide authorized iNaturalist account. Dikarya queues local MycoMap BLAST preparation in the background with a default of 50 hits. If that automatic local refresh fails, the job uses the saved MycoMap results. If `rebuild_ncbi_blast` is true for a single observation, the job queues MycoMap's asynchronous NCBI rerun and is scheduled to resume about 10 minutes later without occupying the phylogeny worker.","requestBody":{"content":{"application/json":{"schema":{"properties":{"keep_existing_tree_url":{"default":false,"description":"For a single observation that already has a Phylogenetic Tree field, build an additional tree and leave the field's current URL unchanged. Takes precedence over `recreate_existing_tree`.","type":"boolean"},"mycomap_local_limit":{"default":50,"description":"Number of local MycoMap BLAST hits to request when the local BLAST results are rebuilt before importing sequences.","maximum":500,"minimum":1,"type":"integer"},"mycomap_ncbi_limit":{"default":100,"description":"Number of NCBI BLAST hits to request when rebuild_ncbi_blast is true.","maximum":500,"minimum":1,"type":"integer"},"observation":{"description":"Either a numeric observation ID (e.g. `360934883`) or a single-observation URL (`https://www.inaturalist.org/observations/<id>`). Search URLs and multiple IDs are rejected.","example":"360934883","maxLength":300,"type":"string"},"rebuild_ncbi_blast":{"default":false,"description":"For single-observation jobs, queue a background MycoMap NCBI BLAST rerun, then schedule the tree to resume about 10 minutes later. Username and project batch jobs reject this.","type":"boolean"},"recreate_existing_tree":{"default":false,"description":"For a single observation that already has a Phylogenetic Tree field, explicitly allow a new tree to replace the field's current URL.","type":"boolean"}},"required":["observation"],"type":"object"}}},"required":true},"responses":{"202":{"description":"Job queued; iNaturalist field will be updated when the tree completes."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Insufficient scope"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited (including per-token concurrent SSE cap)"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal server error"}},"security":[{"bearerAuth":["jobs:write"]}],"summary":"Build a tree from a single iNaturalist observation","tags":["Tools"]}}},"security":[{"bearerAuth":[]}],"servers":[{"url":"https://dikarya.us/api/v1"}],"tags":[{"description":"Identity and token management","name":"Account"},{"description":"Phylogenetic job lifecycle","name":"Jobs"},{"description":"Post-hoc tree mutations","name":"Tree"},{"description":"Auxiliary lookups: BLAST, GenBank","name":"Tools"},{"description":"Liveness ping","name":"Health"}]}
