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/apiThe 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
| Method | Path | Description |
|---|---|---|
| GET | /api/me | Current user identity: { id, name, email, team } |
| GET | /api/account/data | Export all of the team’s data (GDPR) |
| DELETE | /api/account/data | Erase all team data. Owner only; body { "confirm": "<teamId>" } |
Credits & billing
| Method | Path | Description |
|---|---|---|
| GET | /api/billing/credits | Balance: monthlyCredits, usedCredits, remaining, percentUsed, plan, AI analysis quota (bare fields) |
| GET | /api/billing/usage | Recent usage events, newest first. Query: ?limit= (default 100, max 500) |
| GET | /api/dashboard/usage | Usage analytics: daily credit series + AI gateway usage. Query: ?days=7|30|90|180 (default 30) |
| POST | /api/billing/estimate | Cost preview. Body: { "resourceProfile": "gpu" } or { "compute": { "vcpu": 8, "ramGb": 64 } }. Returns allowed, creditPerSecond, creditsPerHour, plan caps (bare fields) |
| GET | /api/billing/invoices | Stripe invoice history (up to 24): id, status, amount, PDF and hosted URLs |
| GET | /api/billing/topup | List available top-up credit packages |
| POST | /api/billing/topup | Start a Stripe Checkout session. Body: { "packageIndex": 0 }. Returns { "url" } |
| POST | /api/billing/checkout | Alias 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
| Method | Path | Description |
|---|---|---|
| GET | /api/workflows | List the team’s workflows |
| POST | /api/workflows | Create. 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
| Method | Path | Description |
|---|---|---|
| GET | /api/runs | List the team’s runs (most recent 50) |
| POST | /api/runs | Start a run — see below |
| GET | /api/runs/{id} | Pollable snapshot: status, logs, errorMessage, outputLocation, durationMs, creditsUsed, timestamps (bare fields) |
| POST | /api/runs/{id}/cancel | Cancel a run. Idempotent for terminal runs; requires a privileged role |
| GET | /api/runs/{id}/events | Durable run-event log, ordered by seq. Query: ?after_seq=N&limit=K (default 100, max 500) for gap-free resume |
| GET | /api/runs/{id}/outputs | Verified output artifacts with short-lived (~15 min) presigned download URLs, SHA-256 and size per file |
| GET | /api/runs/{id}/stream | Live 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 overresourceProfile.resourceProfile— the namedgpupreset (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).
| Method | Path | Description |
|---|---|---|
| GET | /api/files | List the team’s files (uploads first, capped at 2000), each with a presigned download URL (~15 min) |
| POST | /api/files/presign | Get an upload URL. Body: { "filename", "contentType", "size" }. Returns { url, key, method: "PUT" } — PUT the bytes directly to url (5 min expiry) |
| POST | /api/files/delete | Delete one file. Body: { "key", "source": "upload" | "output" } |
| POST | /api/files/delete-run | Delete 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.
| Method | Path | Description |
|---|---|---|
| POST | /api/ai/analyze | Analyze 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/upload | Analyze 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/completions | Authenticated 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.viewerrole is read-only;editormay edit and run the workflow (billed to the owning team):
| Method | Path | Description |
|---|---|---|
| POST | /api/collab/invites | Create 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/join | Public. Redeem { "invite": "bni_…", "name"?: "…" } → workflow definition + editor room credentials; guests also get a runToken for editor-role invites |
| POST | /api/collab/token | Mint a live-collaboration room token for a workflow your team owns (used by the editor’s WebSocket sync — see WebSocket Events) |
Health
| Method | Path | Description |
|---|---|---|
| GET | /api/health | Liveness probe (unauthenticated) |
| GET | /api/health/ready | Readiness probe: env + database checks (503 on failure) |
Errors
| Status | Meaning |
|---|---|
| 400 | Invalid body/params (details in error) |
| 401 | Missing, invalid, or expired session token |
| 402 | Payment/quota barrier (e.g. Free storage cap) |
| 403 | Authenticated but lacks permission / wrong team |
| 404 | Not found (also used for other teams’ resources) |
| 409 | Conflict (e.g. duplicate invite, invalid run outputs) |
| 413 | Payload too large (5 GB file / 20 MB PDF limits) |
| 429 | Rate 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.