---
name: using-the-bios-api
description: >-
  Runs biomedical deep research, literature search, and sandboxed data analysis
  through the BIOS public API (api.ai.bio.xyz) with a BIOS API key (bio_sk_...).
  Covers the REST surface and the bios-deep-research MCP server: starting and
  polling asynchronous deep-research conversations, fast and deep literature
  queries, data-analysis tasks, artifact downloads, and the file upload flow.
  Use when a task mentions BIOS, bio.xyz, BioAgent, deep research, biomedical
  literature review, or analyzing scientific datasets via API, or when the user
  supplies a bio_sk_ API key.
---

<!--
  Canonical consumer doc for the BIOS public API. Keep endpoints, tool names,
  and research modes consistent with apps/public-api/app/mcp_server.py and
  apps/public-api/app/routers/*. Verify against
  https://api.ai.bio.xyz/openapi.json when in doubt.
-->

# Using the BIOS API

BIOS is an AI scientist for biomedical research. Its public API exposes four
capabilities: **deep research** (iterative multi-agent research sessions),
**literature search**, **data analysis** (sandboxed Python), and **file
management**. Everything is reachable two ways — a REST API and an MCP server —
both authenticated with the same BIOS API key.

- **Base URL:** `https://api.ai.bio.xyz`
- **MCP endpoint:** `https://api.ai.bio.xyz/mcp`
- **OpenAPI spec:** `https://api.ai.bio.xyz/openapi.json` (authoritative schema for every endpoint)

## Authentication

Every request carries the API key as a bearer token:

```
Authorization: Bearer bio_sk_...
```

Create a key at **Account Settings → API Keys**
(`https://chat.bio.xyz/chat?settings=account&section=api-keys`). The key is shown
once at creation and starts with `bio_sk_`. Never log it or commit it; revoke and
regenerate from the same page if it leaks.

## REST or MCP?

- **REST** — default for scripts, backends, and any HTTP client.
- **MCP** — for MCP-capable clients (Claude Desktop, Cursor, Windsurf). Setup in
  [MCP setup](#mcp-setup); the client runs an OAuth flow where you paste the same
  `bio_sk_` key once into a consent page.

The two surfaces share per-user rate-limit buckets and USD balance — usage
through one counts against the other.

## Deep research

Asynchronous. You start a conversation, poll until it finishes, then read the
result. Continue the same conversation to refine.

Follow this sequence:

```
1. POST /deep-research/start  (message + researchMode) -> conversationId
2. GET  /deep-research/{conversationId}  -> repeat until status != "in_progress"
3. Read state (objectives, hypotheses, discoveries, insights, datasets)
   and messages (per-cycle research output) from the response
4. To refine: POST /deep-research/start again with the SAME conversationId
```

`POST /deep-research/start` is **form-encoded** (`application/x-www-form-urlencoded`):

| Field | Required | Notes |
|-------|----------|-------|
| `message` | yes | Research question, or follow-up when continuing |
| `researchMode` | no, but **always set it** | `steering`, `semi-autonomous`, or `fully-autonomous` |
| `conversationId` | no | Continue an existing conversation |
| `fileIds` | no | JSON array (`["file_1","file_2"]`) or comma-separated list |

```bash
curl -X POST "https://api.ai.bio.xyz/deep-research/start" \
  -H "Authorization: Bearer bio_sk_..." \
  -d "message=What compounds show senolytic activity in human clinical trials?" \
  -d "researchMode=steering"
```

**Always pass `researchMode` explicitly** to select the intended execution
budget. Research charges depend on measured usage and the active pricing policy:

| Mode | Iterations | Typical duration | Use for |
|------|-----------|------------------|---------|
| `steering` | 1 per call | ~20 min | Step-by-step control; cheapest |
| `semi-autonomous` | up to 5 | ~60 min | Balanced, runs with review pauses |
| `fully-autonomous` | up to 20 | ~8 hrs | Deep, uninterrupted; most expensive |

Poll for progress and read results:

```bash
curl "https://api.ai.bio.xyz/deep-research/{conversationId}" \
  -H "Authorization: Bearer bio_sk_..."
```

`status` is `in_progress` until research completes, then `completed`. Other
deep-research endpoints: `GET /deep-research` (list, paginated),
`GET /deep-research/batch` (detail for several `conversationId` query params),
`GET /deep-research/{conversationId}/artifacts/{artifactId}/download` (presigned
artifact URL).

## File uploads

Upload a file once, then reference its id in deep research or analysis.

**REST** — one multipart request:

```bash
curl -X POST "https://api.ai.bio.xyz/files/upload" \
  -H "Authorization: Bearer bio_sk_..." \
  -F "file=@gene_expression.csv"
```

The response contains the file id. Manage files with `GET /files` (list),
`GET /files/{file_id}` (metadata), `DELETE /files/{file_id}`. Pass ids via the
`fileIds` field of `/deep-research/start` or `/agents/analysis/run`.

**MCP** — a three-step sequence (do not skip `complete_file_upload`):

```
1. bios-deep-research:create_file_upload(filename, content_type, size) -> fileId, uploadUrl
2. HTTP PUT the raw bytes to uploadUrl
3. bios-deep-research:complete_file_upload(file_id) -> finalizes and validates
```

Then thread the returned file ids into `start_deep_research` or
`run_data_analysis`.

## Standalone subagents

Run literature and analysis directly, without a deep-research conversation.

### Literature

`POST /agents/literature/query` is a **JSON** body:

| Field | Required | Notes |
|-------|----------|-------|
| `question` | yes | The research question |
| `mode` | no (default `fast`) | `fast` returns an answer synchronously; `deep` returns a `jobId` |
| `sources` | no | Any of `arxiv`, `pubmed`, `clinical-trials` |
| `maxResults`, `perSourceLimit` | no | Result caps |

```bash
curl -X POST "https://api.ai.bio.xyz/agents/literature/query" \
  -H "Authorization: Bearer bio_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"question": "Latest clinical evidence on senolytics?", "mode": "fast"}'
```

Default to `fast` for a quick synchronous answer. Escalate to `deep` only when
thoroughness is needed, then poll `GET /agents/literature/jobs/{jobId}` until
`status` is `completed`. `GET /agents/literature` lists past literature tasks.

> The standalone literature endpoint searches `arxiv`, `pubmed`, and
> `clinical-trials` only. Deep-research sessions draw on a broader set (patents,
> UniProt, ChEMBL) internally, but those are not valid `sources` values here.

### Data analysis

`POST /agents/analysis/run` is **form-encoded**, always asynchronous:

| Field | Required | Notes |
|-------|----------|-------|
| `taskDescription` | yes | What to compute |
| `fileIds` | no | Repeat the field once per file id (not a JSON array) |

```bash
curl -X POST "https://api.ai.bio.xyz/agents/analysis/run" \
  -H "Authorization: Bearer bio_sk_..." \
  -F "taskDescription=Run PCA and differential expression on the uploaded dataset" \
  -F "fileIds=file_123" \
  -F "fileIds=file_456"
```

Returns a `taskId`. Poll `GET /agents/analysis/tasks/{taskId}` until complete,
then fetch outputs from
`GET /agents/analysis/tasks/{taskId}/artifacts/{artifactId}/download`.
`GET /agents/analysis` lists past analysis tasks.

## Errors and limits

- **401** — invalid API key.
- **403** — missing or malformed `Authorization` header (send `Authorization: Bearer bio_sk_...`).
- **402** — insufficient USD balance. Add funds in the app before retrying.
- **429** — rate limited. Honor the `Retry-After` header. `X-RateLimit-Limit`,
  `X-RateLimit-Remaining`, and `X-RateLimit-Reset` accompany successful REST
  responses and 429s — treat them as advisory and tolerate their absence.

Costs are denominated in USD and depend on model and tool usage. Longer
research runs can cost more. Exact limits and prices are deployment-configured;
check your account for the current balance and pricing rather than assuming
fixed per-request costs. Rate-limit headers describe request limits, not prices.

## MCP setup

Connect an MCP client to `https://api.ai.bio.xyz/mcp`. The client opens a browser
consent page; paste your `bio_sk_` key once to authorize.

**Claude Desktop** — Settings → Connectors → Add custom connector, name `BIOS`,
URL `https://api.ai.bio.xyz/mcp`. For legacy config-file setups:

```json
{
  "mcpServers": {
    "bios-deep-research": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.ai.bio.xyz/mcp"]
    }
  }
}
```

**Cursor** (`.cursor/mcp.json`) / **Windsurf** — register the server under the key
`bios-deep-research` so tools resolve as `bios-deep-research:<tool>`:

```json
{
  "mcpServers": {
    "bios-deep-research": { "url": "https://api.ai.bio.xyz/mcp" }
  }
}
```

## MCP tool reference

15 tools, qualified by the server registration name `bios-deep-research`:

| Tool | Purpose |
|------|---------|
| `bios-deep-research:start_deep_research` | Start or continue a deep research session |
| `bios-deep-research:get_conversation` | Get session detail: status, world state, messages (poll target) |
| `bios-deep-research:list_conversations` | List past deep research sessions |
| `bios-deep-research:create_file_upload` | Create a presigned upload session |
| `bios-deep-research:complete_file_upload` | Finalize and validate an upload |
| `bios-deep-research:list_files` | List uploaded files |
| `bios-deep-research:get_file` | Get file metadata |
| `bios-deep-research:delete_file` | Delete a file |
| `bios-deep-research:query_literature` | Standalone literature search (fast/deep) |
| `bios-deep-research:get_literature_job` | Poll a deep-mode literature job |
| `bios-deep-research:run_data_analysis` | Start a data analysis task |
| `bios-deep-research:get_data_analysis_task` | Poll a data analysis task |
| `bios-deep-research:get_artifact_download_url` | Presigned artifact URL (task or conversation) |
| `bios-deep-research:list_literature_tasks` | List past literature tasks |
| `bios-deep-research:list_analysis_tasks` | List past analysis tasks |

The MCP workflow mirrors REST: `start_deep_research` returns a `conversationId`
immediately, then poll `get_conversation` until `status` is `completed`, and call
`start_deep_research` again with the same `conversationId` to refine.

## Full REST route map

```text
GET    /health
POST   /deep-research/start
GET    /deep-research
GET    /deep-research/batch
GET    /deep-research/{conversationId}
GET    /deep-research/{conversationId}/artifacts/{artifactId}/download
POST   /files/upload
GET    /files
GET    /files/{file_id}
DELETE /files/{file_id}
POST   /agents/literature/query
GET    /agents/literature/jobs/{jobId}
GET    /agents/literature
POST   /agents/analysis/run
GET    /agents/analysis/tasks/{taskId}
GET    /agents/analysis/tasks/{taskId}/artifacts/{artifactId}/download
GET    /agents/analysis
```

For exhaustive request/response schemas, see `https://api.ai.bio.xyz/openapi.json`.
