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.