<!-- Source: https://docs.biosimulant.com/developer-api/rest-reference -->

# REST reference

The Developer API runs versioned Hub labs as durable managed jobs. For the guided path, start with the [Developer API quickstart](/developer-api/quickstart).

## Base URL and authentication

```text
https://api.biosimulant.com/v1
```

Send a scoped API key on every request:

```http
Authorization: Bearer bsk_live_...
```

Every response includes a request ID. Run-creation requests also require `Idempotency-Key`. See [Errors, retries, and rate limits](/developer-api/errors) before implementing production retries.

## Endpoint index

| Method | Path | Purpose |
|---|---|---|
| `GET` | [`/capabilities`](#get-capabilities) | Lists runnable lab versions visible to the API-key owner, including their declared input and output schemas. |
| `GET` | [`/capabilities/{namespace}/{name}`](#get-capabilities-namespace-name) | Resolves the latest accessible version of a named runnable lab and returns its public input and output contract. |
| `GET` | [`/compute-profiles`](#get-compute-profiles) | Lists available compute profiles, their resource limits and credit rates, and the caller’s current credit balance. |
| `POST` | [`/runs`](#post-runs) | Validates a pinned runnable lab, reserves credits, and enqueues a durable managed run. The Idempotency-Key header is required. |
| `GET` | [`/runs`](#get-runs) | Returns the caller’s Developer API runs in reverse chronological order using cursor-based pagination. |
| `GET` | [`/runs/{run_id}`](#get-runs-run-id) | Retrieves the current lifecycle state, timestamps, credit settlement, provenance, and links for an owned run. |
| `GET` | [`/runs/{run_id}/results`](#get-runs-run-id-results) | Returns declared public outputs, completed artifacts, and provenance for a completed owned run. |
| `GET` | [`/runs/{run_id}/events`](#get-runs-run-id-events) | Reads ordered progress and log events after a numeric cursor. Use next_cursor to continue polling without duplicates. |
| `POST` | [`/runs/{run_id}/cancel`](#post-runs-run-id-cancel) | Idempotently requests cancellation of an owned run. Terminal runs are returned unchanged. |
| `GET` | [`/runs/{run_id}/artifacts/{artifact_id}`](#get-runs-run-id-artifacts-artifact-id) | Downloads one completed artifact belonging to an owned run after authorization is rechecked. |

## GET `/capabilities`

Lists runnable lab versions visible to the API-key owner, including their declared input and output schemas.

**Required scope:** `capabilities:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `limit` | query | no | integer | Maximum number of items to return. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/capabilities" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "items": [
    {
      "ref": "demi/microbiology-hello-world-growth@1.0.0",
      "name": "microbiology-hello-world-growth",
      "version": "1.0.0",
      "title": "Microbiology Hello World Growth",
      "inputs": [
        {
          "name": "initial_cells",
          "value_type": "integer",
          "required": true
        }
      ],
      "outputs": [
        {
          "name": "final_cells",
          "value_type": "integer"
        }
      ],
      "package_sha256": "sha256:…"
    }
  ],
  "has_more": false
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/capabilities/{namespace}/{name}`

Resolves the latest accessible version of a named runnable lab and returns its public input and output contract.

**Required scope:** `capabilities:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `namespace` | path | yes | string | Capability-owner namespace. |
| `name` | path | yes | string | Capability package name. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/capabilities/${NAMESPACE}/${NAME}" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "ref": "demi/microbiology-hello-world-growth@1.0.0",
  "name": "microbiology-hello-world-growth",
  "version": "1.0.0",
  "title": "Microbiology Hello World Growth",
  "inputs": [
    {
      "name": "initial_cells",
      "value_type": "integer",
      "required": true
    }
  ],
  "outputs": [
    {
      "name": "final_cells",
      "value_type": "integer"
    }
  ],
  "package_sha256": "sha256:…"
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/compute-profiles`

Lists available compute profiles, their resource limits and credit rates, and the caller’s current credit balance.

**Required scope:** `capabilities:read`

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/compute-profiles" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "items": [
    {
      "id": "00000000-0000-0000-0000-000000000001",
      "name": "standard",
      "display_name": "Standard",
      "cpu_cores": 2,
      "memory_mb": 4096,
      "gpu_type": null,
      "gpu_count": 0,
      "timeout_seconds": 3600,
      "credit_cost_per_minute": 1,
      "minimum_charge_minutes": 1,
      "is_default": true
    }
  ],
  "credit_balance": 100
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## POST `/runs`

Validates a pinned runnable lab, reserves credits, and enqueues a durable managed run. The Idempotency-Key header is required.

**Required scope:** `runs:write`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `Idempotency-Key` | header | no | string or null | Unique key for this logical run-creation request. Reuse only when retrying the same payload. |

### Request body

```json
{
  "ref": "demi/microbiology-hello-world-growth@1.0.0",
  "inputs": {
    "initial_cells": 10,
    "available_food": 80
  },
  "compute_profile": "standard",
  "metadata": {
    "sample_id": "plate-17"
  }
}
```

### Example request

```bash
curl --request POST "https://api.biosimulant.com/v1/runs" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY" \
  --header "Idempotency-Key: growth-sample-17" \
  --header "Content-Type: application/json" \
  --data '{"ref":"demi/microbiology-hello-world-growth@1.0.0","inputs":{"initial_cells":10,"available_food":80},"compute_profile":"standard","metadata":{"sample_id":"plate-17"}}'
```

### 202 response

```json
{
  "id": "00000000-0000-0000-0000-000000000123",
  "status": "queued",
  "ref": "demi/microbiology-hello-world-growth@1.0.0",
  "resolved_ref": "demi/microbiology-hello-world-growth@1.0.0",
  "metadata": {
    "sample_id": "plate-17"
  },
  "compute_profile": "standard",
  "credits_reserved": 5,
  "credits_settled": null,
  "error": null,
  "provenance": {
    "runtime_version": "0.0.19",
    "package_sha256": "sha256:…"
  },
  "links": {
    "self": "/v1/runs/00000000-0000-0000-0000-000000000123",
    "results": "/v1/runs/00000000-0000-0000-0000-000000000123/results",
    "events": "/v1/runs/00000000-0000-0000-0000-000000000123/events"
  }
}
```

### Responses

| Status | Meaning |
|---:|---|
| `202` | Successful Response |
| `400` | Idempotency-Key is missing or invalid. |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `409` | The idempotency key conflicts with another payload, the original request is still processing, or the capability is not ready. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/runs`

Returns the caller’s Developer API runs in reverse chronological order using cursor-based pagination.

**Required scope:** `runs:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `limit` | query | no | integer | Maximum number of items to return. |
| `cursor` | query | no | string or null | Run ID cursor from the preceding page. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/runs" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "items": [
    {
      "id": "00000000-0000-0000-0000-000000000123",
      "status": "completed",
      "resolved_ref": "demi/microbiology-hello-world-growth@1.0.0",
      "metadata": {
        "sample_id": "plate-17"
      }
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/runs/{run_id}`

Retrieves the current lifecycle state, timestamps, credit settlement, provenance, and links for an owned run.

**Required scope:** `runs:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `run_id` | path | yes | string | Owned run UUID. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/runs/${RUN_ID}" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "id": "00000000-0000-0000-0000-000000000123",
  "status": "queued",
  "ref": "demi/microbiology-hello-world-growth@1.0.0",
  "resolved_ref": "demi/microbiology-hello-world-growth@1.0.0",
  "metadata": {
    "sample_id": "plate-17"
  },
  "compute_profile": "standard",
  "credits_reserved": 5,
  "credits_settled": null,
  "error": null,
  "provenance": {
    "runtime_version": "0.0.19",
    "package_sha256": "sha256:…"
  },
  "links": {
    "self": "/v1/runs/00000000-0000-0000-0000-000000000123",
    "results": "/v1/runs/00000000-0000-0000-0000-000000000123/results",
    "events": "/v1/runs/00000000-0000-0000-0000-000000000123/events"
  }
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/runs/{run_id}/results`

Returns declared public outputs, completed artifacts, and provenance for a completed owned run.

**Required scope:** `runs:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `run_id` | path | yes | string | Owned run UUID. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/runs/${RUN_ID}/results" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "run_id": "00000000-0000-0000-0000-000000000123",
  "outputs": {
    "final_cells": 42
  },
  "artifacts": [],
  "provenance": {
    "runtime_version": "0.0.19",
    "package_sha256": "sha256:…"
  }
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `409` | The run has not completed, so results are not ready. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/runs/{run_id}/events`

Reads ordered progress and log events after a numeric cursor. Use next_cursor to continue polling without duplicates.

**Required scope:** `runs:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `run_id` | path | yes | string | Owned run UUID. |
| `after` | query | no | integer | Return events with a cursor greater than this value. |
| `limit` | query | no | integer | Maximum number of items to return. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/runs/${RUN_ID}/events" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "items": [
    {
      "cursor": 12,
      "timestamp": "2026-07-19T12:00:00Z",
      "level": "info",
      "source": "runtime",
      "type": "run.progress",
      "message": "Simulation reached day 50",
      "data": {
        "progress": 0.5
      }
    }
  ],
  "next_cursor": 12
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## POST `/runs/{run_id}/cancel`

Idempotently requests cancellation of an owned run. Terminal runs are returned unchanged.

**Required scope:** `runs:write`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `run_id` | path | yes | string | Owned run UUID. |

### Example request

```bash
curl --request POST "https://api.biosimulant.com/v1/runs/${RUN_ID}/cancel" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

```json
{
  "id": "00000000-0000-0000-0000-000000000123",
  "status": "queued",
  "ref": "demi/microbiology-hello-world-growth@1.0.0",
  "resolved_ref": "demi/microbiology-hello-world-growth@1.0.0",
  "metadata": {
    "sample_id": "plate-17"
  },
  "compute_profile": "standard",
  "credits_reserved": 5,
  "credits_settled": null,
  "error": null,
  "provenance": {
    "runtime_version": "0.0.19",
    "package_sha256": "sha256:…"
  },
  "links": {
    "self": "/v1/runs/00000000-0000-0000-0000-000000000123",
    "results": "/v1/runs/00000000-0000-0000-0000-000000000123/results",
    "events": "/v1/runs/00000000-0000-0000-0000-000000000123/events"
  }
}
```

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## GET `/runs/{run_id}/artifacts/{artifact_id}`

Downloads one completed artifact belonging to an owned run after authorization is rechecked.

**Required scope:** `runs:read`

### Parameters

| Name | In | Required | Type | Description |
|---|---|---:|---|---|
| `run_id` | path | yes | string | Owned run UUID. |
| `artifact_id` | path | yes | string | Artifact identifier returned by the results endpoint. |

### Example request

```bash
curl --request GET "https://api.biosimulant.com/v1/runs/${RUN_ID}/artifacts/${ARTIFACT_ID}" \
  --header "Authorization: Bearer $BIOSIMULANT_API_KEY"
```

### 200 response

The response body is the authorized artifact binary. Use the returned `Content-Type` and `Content-Disposition` headers when saving it.

### Responses

| Status | Meaning |
|---:|---|
| `200` | Successful Response |
| `401` | Missing, invalid, expired, or revoked API key. |
| `403` | The API key does not have the required scope. |
| `404` | The requested capability, run, or artifact was not found or is not visible. |
| `422` | Validation Error |
| `429` | The API-key or run-creation rate limit was exceeded. Respect Retry-After. |
| `500` | The service could not complete the request. Retain the response request ID. |

## Machine-readable specification

The [OpenAPI 3.1 document](/openapi/developer-v1.json) is generated from the backend routes, enriched with production examples and error responses, and verified with this site.
