SUBSEQ.BIO
DOCS-API

API Reference v1

Base URL: https://subseq.bio/api/v1. Every response follows { "success": bool, "data"?: any, "error"?: string }. Send Authorization: Bearer <api_key> (or rely on the api_key cookie).

In every job container, your uploaded or referenced data is mounted read-only at /inputs/, and auxiliary data is mounted read-only at /aux/. Write any results to /outputs/ so they are collected and downloadable.

Rate limits

Per client IP: token bucket with burst of 10 requests, averaging ~6 req/s. Global: 800 requests per 10 seconds across all clients. If you receive HTTP 429, honor the Retry-After header (seconds to wait) or back off with exponential jitter.

Jobs

POST /job/submit

Launch a job via multipart/form-data. Include program, repeatable args, input_src (none | upload | dataset | job), and matching fields (folder, digest, from_job). Optional fields include project, memo, deadline_minutes, aux_src (dataset | job), aux_ref, and auxiliary file uploads via aux form fields (uploaded into /aux).

Upload limits: request body up to 64 GiB total, and up to 20,000 files per upload field (folder and aux each).

curl -X POST https://subseq.bio/api/v1/job/submit \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -F program=alphafold2 \
    -F input_src=upload \
    -F memo="Benchmark run 12" \
    -F args=--fasta_paths=data/sample.fasta \
    -F "folder=@data/sample.fasta;filename=data/sample.fasta"
{
  "success": true,
  "data": {
    "job_id": "5bf2d83e40a47cf5"
  }
}

GET /job/list

List jobs (query params: limit <=100, offset, status, project, program, before=YYYY-MM-DD). Each row includes input_src/input_ref and aux_src/aux_ref when the job depended on prior data, plus memo if one was provided.

curl -G https://subseq.bio/api/v1/job/list \
    -H "Authorization: Bearer sk-ss-admin-123" \
    --data-urlencode "limit=5" \
    --data-urlencode "status=completed" \
    --data-urlencode "program=alphafold2"
{
  "success": true,
  "data": {
    "total": 12,
    "jobs": [
      {
        "job_id": "5bf2d83e40a47cf5",
        "status": "completed",
        "cost": 18.5,
        "program": "alphafold2",
        "input_src": "dataset",
        "input_ref": "08f9f54a1d55e548e54a9b857f2df70f44c2bcfe6ff5b846c8d3107568e1b6d9",
        "project": "default",
        "memo": "Benchmark run 12",
        "aux_src": "job",
        "aux_ref": "5bf2d83e40a47cf4",
        "created_at": 1730678400,
        "started_at": 1730678465,
        "finished_at": 1730680200,
        "last_charged_at": 1730679600
      }
    ]
  }
}

GET /job/view

Inspect a single job; requires jobid query. Returns input_src/input_ref and aux_src/aux_ref when the job used a dataset or another job as its source (omitted for generated jobs). Includes memo if provided and a manifest for finished jobs.

curl "https://subseq.bio/api/v1/job/view?jobid=5bf2d83e40a47cf5" \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": {
    "status": "completed",
    "cost": 18.5,
    "program": "alphafold2",
    "user_args": "--fasta_paths=data/sample.fasta",
    "server_args": "--max_template_date=2023-10-01",
    "project": "default",
    "memo": "Benchmark run 12",
    "input_src": "job",
    "input_ref": "5bf2d83e40a47cf4",
    "aux_src": "dataset",
    "aux_ref": "08f9f54a1d55e548e54a9b857f2df70f44c2bcfe6ff5b846c8d3107568e1b6d9",
    "created_at": 1730678400,
    "started_at": 1730678465,
    "finished_at": 1730680200,
    "log_tail": "Job finished successfully.",
    "manifest": [
      {
        "path": "outputs/prediction.pdb",
        "sha256": "b3b0bf9cf3b5c7d98a7d4012ee6324de470b01fb6bc2cbbb0f1e46f9d3db15bc",
        "size": 2456789
      }
    ]
  }
}

POST /job/cancel

Cancel a pending or running job via ?jobid=.

curl -X POST "https://subseq.bio/api/v1/job/cancel?jobid=5bf2d83e40a47cf5" \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": "Job cancelled successfully"
}

GET /job/download

Download the job archive ZIP (?jobid=, optional accept_partial_data=true for failed/canceled jobs).

curl -L -o job_5bf2d83e40a47cf5.zip \
    "https://subseq.bio/api/v1/job/download?jobid=5bf2d83e40a47cf5" \
    -H "Authorization: Bearer sk-ss-admin-123"
HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="job_5bf2d83e40a47cf5.zip"

GET /job/file

Stream a single output (?jobid= & path= from manifest). Supports GET/HEAD.

curl -H "Authorization: Bearer sk-ss-admin-123" \
    "https://subseq.bio/api/v1/job/file?jobid=5bf2d83e40a47cf5&path=outputs/prediction.pdb" \
  | head
HTTP/1.1 200 OK
Content-Type: chemical/x-pdb
X-Subseq-File: 1
...raw file bytes...

POST /job/move-project

Reassign a job to an existing project (empty project removes assignment).

curl -X POST https://subseq.bio/api/v1/job/move-project \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"job_id":"5bf2d83e40a47cf5","project":"archive"}'
{
  "success": true
}

Datasets

POST /dataset/new

Create a dataset: provide project, name, and either upload files via folder parts or set from_job to copy job outputs.

Upload limits: request body up to 64 GiB total, and up to 20,000 files in folder.

curl -X POST https://subseq.bio/api/v1/dataset/new \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -F project=default \
    -F name=models-2025-10-01 \
    -F "folder=@outputs/prediction.pdb;filename=prediction.pdb"
{
  "success": true,
  "data": {
    "digest": "a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a"
  }
}

POST /dataset/delete

Delete by ?digest= or ?name=&project=.

curl -X POST "https://subseq.bio/api/v1/dataset/delete?digest=a3d0...c8a" \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true
}

GET /dataset/info

Inspect dataset metadata (?digest= or ?name=&project=).

curl "https://subseq.bio/api/v1/dataset/info?digest=a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a" \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": {
    "files": [
      {
        "path": "prediction.pdb",
        "sha256": "936a1ec533d4c0bb7e90bcab44cbb6f4c012cfc16f0bcdf5ddf5d24c9fd4da45",
        "size": 2456789
      }
    ],
    "meta": {
      "name": "models-2025-10-01",
      "digest": "a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a",
      "project": "default",
      "job_id": "5bf2d83e40a47cf5",
      "size": 2456789,
      "ready": true,
      "dl_ready": true,
      "created_at": "2025-10-01T17:20:45Z"
    }
  }
}

GET /dataset/list

List datasets (query: limit, offset, project).

curl -G https://subseq.bio/api/v1/dataset/list \
    -H "Authorization: Bearer sk-ss-admin-123" \
    --data-urlencode "limit=10"
{
  "success": true,
  "data": {
    "total": 4,
    "datasets": [
      {
        "digest": "a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a",
        "name": "models-2025-10-01",
        "project": "default",
        "job_id": "5bf2d83e40a47cf5",
        "size": 2456789,
        "ready": true,
        "dl_ready": true,
        "created_at": 1730410800
      }
    ]
  }
}

GET /dataset/download

Download the dataset archive ZIP (available when dl_ready is true).

curl -L -o dataset_a3d0f65b.zip \
    "https://subseq.bio/api/v1/dataset/download?digest=a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a" \
    -H "Authorization: Bearer sk-ss-admin-123"
HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="dataset_a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a.zip"

GET /dataset/file

Stream a file from a ready dataset (?digest= & path=).

curl -H "Authorization: Bearer sk-ss-admin-123" \
    "https://subseq.bio/api/v1/dataset/file?digest=a3d0...c8a&path=prediction.pdb" \
  | head
HTTP/1.1 200 OK
Content-Type: chemical/x-pdb
X-Subseq-File: 1
...raw file bytes...

POST /dataset/move-project

Move a dataset to an existing project (or clear by sending an empty string).

curl -X POST https://subseq.bio/api/v1/dataset/move-project \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"digest":"a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a","project":"archive"}'
{
  "success": true
}

Presigned downloads

Mint short-lived, unauthenticated download links using a stateless HMAC-signed token. The minted link can be opened in a browser or shared with someone who should be able to download the data. The token expires after ttl_seconds (default: 3600; max: 604800).

Server config: requires SUBSEQ_PRESIGN_HMAC_SECRET to be set. All presigned downloads require dl_ready=true in the DB.

POST /download/presign

Authenticated endpoint to mint a presigned URL.

type is one of: job_download, job_file, dataset_download, dataset_file.

curl -X POST https://subseq.bio/api/v1/download/presign \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{
  "type": "job_download",
  "jobid": "5bf2d83e40a47cf5",
  "ttl_seconds": 3600
}'
{
  "success": true,
  "data": {
    "url": "https://subseq.bio/d?token=...",
    "token": "...",
    "expires_at": 1730683800
  }
}

For failed/canceled jobs, include "accept_partial_data": true when minting job_download.

Mint a presigned URL for a single job file:

curl -X POST https://subseq.bio/api/v1/download/presign \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{
  "type": "job_file",
  "jobid": "5bf2d83e40a47cf5",
  "path": "outputs/prediction.pdb",
  "ttl_seconds": 600
}'

Mint a presigned URL for a dataset archive:

curl -X POST https://subseq.bio/api/v1/download/presign \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{
  "type": "dataset_download",
  "digest": "a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a",
  "ttl_seconds": 3600
}'

Mint a presigned URL for a single dataset file:

curl -X POST https://subseq.bio/api/v1/download/presign \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{
  "type": "dataset_file",
  "digest": "a3d0f65ba9e14fdb8a95d9f31f4bc7b7ca5f2d93e8f12c6d42c439ab20c77c8a",
  "path": "prediction.pdb",
  "ttl_seconds": 600
}'

GET /download

Unauthenticated download endpoint. Provide the presigned token as a query parameter. Returns either a ZIP archive or a single file, depending on the token type.

curl -L -o out.zip "https://subseq.bio/d?token=..."
HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="job_5bf2d83e40a47cf5.zip"

Projects

POST /project/new

Create (or idempotently ensure) a project name.

curl -X POST https://subseq.bio/api/v1/project/new \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"name":"archive"}'
{
  "success": true
}

GET /project/list

Return all projects for the account.

curl https://subseq.bio/api/v1/project/list \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": [
    { "name": "archive", "created_at": 1730238000 },
    { "name": "default", "created_at": 1728000000 }
  ]
}

POST /project/delete

Delete a project and clear it from jobs/datasets.

curl -X POST https://subseq.bio/api/v1/project/delete \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"name":"archive"}'
{
  "success": true
}

Public

GET /status

Cluster heartbeat.

curl https://subseq.bio/api/v1/status
{
  "success": true
}

GET /program/list

List active programs with pricing info.

curl https://subseq.bio/api/v1/program/list
{
  "success": true,
  "data": [
    {
      "name": "alphafold2",
      "display_name": "AlphaFold2",
      "description": "AlphaFold2 monomer inference with reduced DBs.",
      "cost_per_hour": 14.5,
      "submit_fee": 0,
      "min_run_time": 900
    }
  ]
}

GET /pricing

Current submit fee (credits). This is 0 - jobs have no upfront charge.

curl https://subseq.bio/api/v1/pricing
{
  "success": true,
  "data": {
    "submit_fee": 0
  }
}

Auth & Account

POST /auth/otp

Send a one-time code to email ({ "email": string }).

curl -X POST https://subseq.bio/api/v1/auth/otp \
    -H "Content-Type: application/json" \
    -d '{"email":"you@example.com"}'
{
  "success": true
}

POST /auth/login

Exchange OTP for an admin API key. type=api returns the key; web sets the cookie.

curl -X POST https://subseq.bio/api/v1/auth/login \
    -H "Content-Type: application/json" \
    -d '{"email":"you@example.com","otp":"123456","type":"api"}'
{
  "success": true,
  "data": {
    "token": "sk-ss-admin-123",
    "expires_at": 1733107200
  }
}

GET /account/info

Retrieve credits and metadata.

curl https://subseq.bio/api/v1/account/info \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": {
    "email": "you@example.com",
    "credits": 87.5,
    "created_at": 1693526400,
    "last_activity": 1733073600
  }
}

POST /account/logout

Invalidate the current admin key (Authorization header or cookie).

curl -X POST https://subseq.bio/api/v1/account/logout \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true
}

API Keys

Requires an admin key from /auth/login. Returned keys are non-admin client keys.

GET /key/list

List non-admin keys.

curl https://subseq.bio/api/v1/key/list \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": [
    {
      "key_hash": "api_9ad2f7...",
      "hint": "sk-ss-api-13****",
      "label": "cli",
      "expires_at": 1734316800
    }
  ]
}

POST /key/new

Create a non-admin key (optional label, expires_in_days).

curl -X POST https://subseq.bio/api/v1/key/new \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"label":"cli","expires_in_days":30}'
{
  "success": true,
  "data": {
    "key": "sk-ss-api-13abcdefg"
  }
}

POST /key/delete

Delete a non-admin key by key_hash.

curl -X POST https://subseq.bio/api/v1/key/delete \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"key_hash":"api_9ad2f7..."}'
{
  "success": true
}

Payments

POST /payment/create-checkout

Create a Stripe Checkout session ({ "credits": int }, 1-1000).

curl -X POST https://subseq.bio/api/v1/payment/create-checkout \
    -H "Authorization: Bearer sk-ss-admin-123" \
    -H "Content-Type: application/json" \
    -d '{"credits":50}'
{
  "success": true,
  "data": {
    "url": "https://checkout.stripe.com/c/pay/cs_test_a1b2..."
  }
}

GET /payment/verify

Finalize a Stripe payment (?session_id=, ?tx= from checkout).

curl "https://subseq.bio/api/v1/payment/verify?session_id=cs_test_a1b2&tx=tx-6f828251" \
    -H "Authorization: Bearer sk-ss-admin-123"
{
  "success": true,
  "data": {
    "url": "https://subseq.bio"
  }
}

GET /tx/list

List transactions (query: limit, offset, status=pending|success|failed|any).

curl -G https://subseq.bio/api/v1/tx/list \
    -H "Authorization: Bearer sk-ss-admin-123" \
    --data-urlencode "limit=5"
{
  "success": true,
  "data": {
    "total": 3,
    "txs": [
      {
        "txid": "tx-6f828251",
        "user_id": 42,
        "email": "you@example.com",
        "amount": 50,
        "currency": "usd",
        "status": "success",
        "created_at": 1733071800,
        "completed_at": 1733071860
      }
    ]
  }
}

Error Model

Failures use HTTP 4xx/5xx with {"success": false, "error": "message"}. Common cases: 400 invalid input, 401 missing/expired auth, 403 insufficient credits or non-admin, 404 missing resource, 429 rate limit, 503 cluster offline.