> ## Documentation Index
> Fetch the complete documentation index at: https://docs.strandai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# R SDK

> Install the strandai R SDK, configure an API key, upload H&E slides, submit marker predictions, and load results as a SpatialExperiment for Bioconductor.

The R SDK (`strandai`) provides the same surface as the Python SDK with
idiomatic R conventions: all functions are prefixed `strand_*` and results
can be returned as a [`SpatialExperiment`](https://bioconductor.org/packages/SpatialExperiment/)
for downstream Bioconductor pipelines.

<Note>
  The package **`strandai`** avoids a CRAN clash with the
  unrelated [`strand`](https://cran.r-project.org/package=strand) package.
</Note>

## Install

```r theme={null}
# From r-universe (when published):
install.packages(
  "strandai",
  repos = c("https://strand-ai.r-universe.dev", "https://cloud.r-project.org")
)

# Or directly from GitHub (bleeding edge):
remotes::install_github("Strand-AI/strand-sdk-r")
```

To get results as a `SpatialExperiment` (recommended) you'll also need:

```r theme={null}
BiocManager::install("SpatialExperiment")
```

## Configuration

| Source | Argument / variable            | Default                    |
| ------ | ------------------------------ | -------------------------- |
| Arg    | `strand_client(api_key = ...)` | reads env                  |
| Env    | `STRAND_API_KEY`               | required                   |
| Env    | `STRAND_BASE_URL`              | `https://app.strandai.com` |

```r theme={null}
library(strandai)
client <- strand_client()                       # reads STRAND_API_KEY
client <- strand_client(api_key = "sk-strand-…") # explicit
```

## End-to-end

```r theme={null}
upload <- strand_upload_file(client, "biopsy.svs", progress = TRUE)

est <- strand_estimate(client, upload$id, c("CD8", "PanCK", "Ki67"))
message("will cost ~", est$estimated_credits, " credits")

job <- strand_predict(client, upload$id, c("CD8", "PanCK", "Ki67"))
status <- strand_job_wait(job, progress = TRUE)

spe <- strand_download_results(job)   # SpatialExperiment
```

### Selecting a model

`strand_predict()` and `strand_run()` accept an optional `model =`. Live
Lattice versions:

* `"v0.4"`: 192-marker panel, original training.
* `"v0.5"`: 192-marker panel, retrained (current default).

Both share the same GenePT embeddings, so the marker vocabulary is identical
between them. Picking a version swaps the model weights while keeping the same
vocabulary.
Omit `model` (or pass `NULL`) to let the platform pick the current default
(`"v0.5"`).

```r theme={null}
result <- strand_run(
  client, "slide.svs",
  markers = c("CD8", "Ki67", "PanCK"),
  model = "v0.5"
)
```

The earlier `"v10"`, `"v10-fullpanel"`, and `"v10-fullpanel-v2"` names are
still accepted as deprecated aliases with a `warning()`; pin the canonical
`v0.X` id to silence the warning and forward-protect against the 2026-12-01
alias sunset. The `"v10"` alias resolved to the now-sunset v0.3 and is
rejected by the server with 400 `unknown_model`.

### Submit without waiting

A full pipeline run blocks for 15+ minutes. To kick a job off and continue
with other work, pass `wait = FALSE`, and `strand_run()` returns the
`strand_job` handle as soon as upload + submit complete:

```r theme={null}
job <- strand_run(client, "slide.svs", c("CD3", "CD8"), wait = FALSE)
message("submitted ", job$id)

# ...do other work, or shut down the process. The job runs server-side.

# Later (same process or a fresh one via `strand_job_get(client, job$id)`):
status <- strand_job_wait(job)
spe <- strand_download_results(job)
```

When `wait = FALSE`, the `"wait"` and `"download"` progress stages don't
fire, and `timeout_sec` / `poll_interval_sec` / `output_dir` are ignored.

## Function reference

| Function                                                    | What it does                                                       |
| ----------------------------------------------------------- | ------------------------------------------------------------------ |
| `strand_client(api_key, base_url)`                          | Construct a client handle.                                         |
| `strand_upload_file(client, path, progress)`                | Resumable chunked upload of a WSI to GCS.                          |
| `strand_estimate(client, upload_id, markers)`               | Compute credit cost without reserving.                             |
| `strand_predict(client, upload_id, markers, model)`         | Submit a prediction; reserves credits.                             |
| `strand_run(client, image_path, markers, model, wait, ...)` | Full pipeline; `wait = FALSE` returns a `strand_job` after submit. |
| `strand_job_get(client, job_id)`                            | Refetch a job snapshot.                                            |
| `strand_job_wait(job, progress, timeout)`                   | Block until terminal status.                                       |
| `strand_download_results(job)`                              | Return results as `SpatialExperiment`.                             |

## Error handling

Documented HTTP error codes map to typed conditions you can dispatch on:

| HTTP | Condition class                                          |
| ---- | -------------------------------------------------------- |
| 400  | `strand_bad_request_error`                               |
| 401  | `strand_auth_error`                                      |
| 402  | `strand_insufficient_credits_error` (carries `required`) |
| 404  | `strand_not_found_error`                                 |
| 429  | `strand_rate_limit_error` (carries `retry_after`)        |

```r theme={null}
tryCatch(
  strand_predict(client, upload$id, markers),
  strand_insufficient_credits_error = function(e) {
    message("need ", e$required, " credits; top up the org first.")
  },
  strand_rate_limit_error = function(e) {
    message("wait ", e$retry_after, "s before retrying.")
  }
)
```

## See also

* [Quickstart](/quickstart): five-minute walkthrough.
* [REST API overview](/api/overview): the underlying HTTP surface.
* [Pricing](/pricing): how credits map to slides × markers.
