APIREST API Reference

REST API Reference

The BioNodulo cloud platform’s REST API lets you manage workflows, runs, files, credits, and AI analyses programmatically. Base URL:

https://bionodulo.com/api

The same API is served on the cloud host (https://cloud.bionodulo.com/api) — both origins run the same app.

All requests require authentication — see Authentication. Most endpoints accept either the same-origin Clerk session cookie or a cross-origin Authorization: Bearer <clerk session JWT>, plus an optional X-Team-Id header to select the team context on the bearer path (membership is verified).

Conventions

  • Response envelope. Most endpoints return { "success": true, "data": ... } on success and { "success": false, "error": "..." } on failure. A few older routes (credits, estimate, run status) return bare fields instead — noted below.
  • Team scoping. Every resource is scoped to the caller’s active team (Clerk organization). Objects belonging to other teams return 404.
  • Roles. Owner/admin/member/viewer are enforced per endpoint (e.g. viewers cannot create runs or upload files).
  • Rate limits. Middleware-level per-IP limits apply (e.g. 30 run submissions per minute); AI endpoints have additional daily fair-use caps.

Account

MethodPathDescription
GET/api/meCurrent user identity: { id, name, email, team }
GET/api/account/dataExport all of the team’s data (GDPR)
DELETE/api/account/dataErase all team data. Owner only; body { "confirm": "<teamId>" }

Credits & billing

MethodPathDescription
GET/api/billing/creditsBalance: monthlyCredits, usedCredits, remaining, percentUsed, plan, AI analysis quota (bare fields)
GET/api/billing/usageRecent usage events, newest first. Query: ?limit= (default 100, max 500)
GET/api/dashboard/usageUsage analytics: daily credit series + AI gateway usage. Query: ?days=7|30|90|180 (default 30)
POST/api/billing/estimateCost preview. Body: { "resourceProfile": "gpu" } or { "compute": { "vcpu": 8, "ramGb": 64 } }. Returns allowed, creditPerSecond, creditsPerHour, plan caps (bare fields)
GET/api/billing/invoicesStripe invoice history (up to 24): id, status, amount, PDF and hosted URLs
GET/api/billing/topupList available top-up credit packages
POST/api/billing/topupStart a Stripe Checkout session. Body: { "packageIndex": 0 }. Returns { "url" }
POST/api/billing/checkoutAlias of top-up POST (same body/response)

Subscription plans are managed with Clerk Billing in Settings → Billing; one-time credit top-ups go through Stripe Checkout.

Workflows

MethodPathDescription
GET/api/workflowsList the team’s workflows
POST/api/workflowsCreate. Body: { "name": "...", "description": "..." }. Returns the created workflow (201)
GET/api/workflows/{id}Get one workflow, including its definition graph
PUT/api/workflows/{id}Update. Body (all optional): name, description, definition
DELETE/api/workflows/{id}Delete. Admins/owners any; members only their own

Runs

MethodPathDescription
GET/api/runsList the team’s runs (most recent 50)
POST/api/runsStart a run — see below
GET/api/runs/{id}Pollable snapshot: status, logs, errorMessage, outputLocation, durationMs, creditsUsed, timestamps (bare fields)
POST/api/runs/{id}/cancelCancel a run. Idempotent for terminal runs; requires a privileged role
GET/api/runs/{id}/eventsDurable run-event log, ordered by seq. Query: ?after_seq=N&limit=K (default 100, max 500) for gap-free resume
GET/api/runs/{id}/outputsVerified output artifacts with short-lived (~15 min) presigned download URLs, SHA-256 and size per file
GET/api/runs/{id}/streamLive progress over Server-Sent Events — see WebSocket Events

Run status is one of queued, running, completed, failed, cancelled, interrupted.

Start a run

POST /api/runs
Content-Type: application/json
 
{
  "workflowId": "9f1c...",
  "compute": { "vcpu": 8, "ramGb": 64 },
  "parameters": {},
  "inputs": {}
}
  • workflowId (required) — a workflow owned by your team.
  • compute — custom size (vcpu + ramGb, min 4 GB per vCPU). A custom spec takes precedence over resourceProfile.
  • resourceProfile — the named gpu preset (T4, 4 vCPU / 16 GB) for accelerator workloads; it is the only named preset.
  • parameters, inputs — optional workflow parameter values and input files.

Response: { "success": true, "data": { "runId": "...", "status": "queued" } }. The Free plan is capped at 4 vCPU / 16 GB and 1-hour runs; paid plans choose any CPU/RAM (billed per second). Use /api/billing/estimate to preview the rate.

Share-link guests holding an editor-role invite token (Authorization: Bearer bni_…) may run the workflow named on their invite; the run is billed to the owning team. See Team collaboration.

Files

Files live in team-scoped object storage (uploads and run outputs).

MethodPathDescription
GET/api/filesList the team’s files (uploads first, capped at 2000), each with a presigned download URL (~15 min)
POST/api/files/presignGet an upload URL. Body: { "filename", "contentType", "size" }. Returns { url, key, method: "PUT" } — PUT the bytes directly to url (5 min expiry)
POST/api/files/deleteDelete one file. Body: { "key", "source": "upload" | "output" }
POST/api/files/delete-runDelete every file a run produced/consumed. Body: { "runId" }

Upload limits: 5 GB per file; executable/script file types are rejected (415); the Free plan’s 5 GB storage cap is enforced at presign time (402 when exceeded). Paid-plan storage is metered at 3 credits per GB-month.

AI

Paper analysis (DOI/PDF) is free for everyone — no account or credits — within a daily fair-use cap (currently 20/day per visitor or team, resetting at 00:00 UTC). The hosted chat model is free for signed-in users.

MethodPathDescription
POST/api/ai/analyzeAnalyze a paper by DOI. Body: { "doi": "10.…" }. Returns { analysisId, status, result: { summary, methodology, workflowSuggestion, paper } }; cached results return instantly. Send Accept: text/event-stream to stream progress events ending in a final event. 409 closed_access means upload the PDF instead
POST/api/ai/uploadAnalyze an uploaded PDF (closed-access fallback). multipart/form-data with file (≤ 20 MB), optional doi and title
GET/api/ai/status?id= or ?doi=Fetch a persisted analysis (team-scoped)
POST/api/ai/proxy/v1/chat/completionsAuthenticated chat proxy (OpenAI Chat Completions wire format, streaming supported). The requested model is replaced by the hosted model; 429 global_quota_exhausted when the shared daily quota is spent

Sharing & collaboration

Two distinct mechanisms:

  • Team membership — invite collaborators by email (Clerk Organizations sends the invitation; they appear as team members on accept):

    POST /api/team/invite
    { "email": "colleague@lab.org", "role": "member" }   // or "admin" (owner/admin only)
  • Share links — per-workflow invite links (bni_… tokens) that open the workflow in the editor without an account. viewer role is read-only; editor may edit and run the workflow (billed to the owning team):

MethodPathDescription
POST/api/collab/invitesCreate a link. Body: { "workflowId", "role": "viewer"|"editor", "expiresInHours"?: 1–720, "maxUses"?: 1–1000 }. Returns the token and a ready-to-share link
GET/api/collab/invites?workflowId=List a workflow’s invites
DELETE/api/collab/invites?id=Revoke an invite (immediate)
POST/api/collab/joinPublic. Redeem { "invite": "bni_…", "name"?: "…" } → workflow definition + editor room credentials; guests also get a runToken for editor-role invites
POST/api/collab/tokenMint a live-collaboration room token for a workflow your team owns (used by the editor’s WebSocket sync — see WebSocket Events)

Health

MethodPathDescription
GET/api/healthLiveness probe (unauthenticated)
GET/api/health/readyReadiness probe: env + database checks (503 on failure)

Errors

StatusMeaning
400Invalid body/params (details in error)
401Missing, invalid, or expired session token
402Payment/quota barrier (e.g. Free storage cap)
403Authenticated but lacks permission / wrong team
404Not found (also used for other teams’ resources)
409Conflict (e.g. duplicate invite, invalid run outputs)
413Payload too large (5 GB file / 20 MB PDF limits)
429Rate limit or daily AI fair-use cap — back off

Real-time

For live run progress, use the SSE stream (GET /api/runs/{id}/stream) or poll GET /api/runs/{id} — see WebSocket Events.