---
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 credit 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.** There is no default — omit it and the
request is charged at the highest (fully-autonomous) credit rate, even though the
session then runs in semi-autonomous mode. Set the mode you want to avoid
overpaying:

| 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 credits. Top up in the app; do not retry the same call.
- **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.

Relative credit cost: literature queries are cheapest, data analysis is moderate,
and deep research is most expensive, scaling with `researchMode`
(`steering` < `semi-autonomous` < `fully-autonomous`). Exact limits and prices
are deployment-configured — read the live values from response headers and your
account rather than assuming fixed numbers.

## 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`.
